notedeck

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

contacts_list.rs (3688B)


      1 use std::collections::HashSet;
      2 
      3 use crate::ProfilePic;
      4 use egui::{RichText, Sense};
      5 use enostr::Pubkey;
      6 use nostrdb::{Ndb, Transaction};
      7 use notedeck::{
      8     name::get_display_name, profile::get_profile_url, DragResponse, Images, MediaJobSender,
      9 };
     10 
     11 pub struct ContactsListView<'a, 'txn> {
     12     contacts: ContactsCollection<'a>,
     13     jobs: &'a MediaJobSender,
     14     ndb: &'a Ndb,
     15     img_cache: &'a mut Images,
     16     txn: &'txn Transaction,
     17 }
     18 
     19 #[derive(Clone)]
     20 pub enum ContactsListAction {
     21     Select(Pubkey),
     22 }
     23 
     24 pub enum ContactsCollection<'a> {
     25     Vec(&'a Vec<Pubkey>),
     26     Set(&'a HashSet<Pubkey>),
     27 }
     28 
     29 pub enum ContactsIter<'a> {
     30     Vec(std::slice::Iter<'a, Pubkey>),
     31     Set(std::collections::hash_set::Iter<'a, Pubkey>),
     32 }
     33 
     34 impl<'a> ContactsCollection<'a> {
     35     pub fn iter(&'a self) -> ContactsIter<'a> {
     36         match self {
     37             ContactsCollection::Vec(v) => ContactsIter::Vec(v.iter()),
     38             ContactsCollection::Set(s) => ContactsIter::Set(s.iter()),
     39         }
     40     }
     41 }
     42 
     43 impl<'a> Iterator for ContactsIter<'a> {
     44     type Item = &'a Pubkey;
     45 
     46     fn next(&mut self) -> Option<Self::Item> {
     47         match self {
     48             ContactsIter::Vec(iter) => iter.next().as_ref().copied(),
     49             ContactsIter::Set(iter) => iter.next().as_ref().copied(),
     50         }
     51     }
     52 }
     53 
     54 impl<'a, 'txn> ContactsListView<'a, 'txn> {
     55     pub fn new(
     56         contacts: ContactsCollection<'a>,
     57         jobs: &'a MediaJobSender,
     58         ndb: &'a Ndb,
     59         img_cache: &'a mut Images,
     60         txn: &'txn Transaction,
     61     ) -> Self {
     62         ContactsListView {
     63             contacts,
     64             ndb,
     65             img_cache,
     66             txn,
     67             jobs,
     68         }
     69     }
     70 
     71     pub fn ui(&mut self, ui: &mut egui::Ui) -> DragResponse<ContactsListAction> {
     72         let mut action = None;
     73 
     74         egui::ScrollArea::vertical().show(ui, |ui| {
     75             let clip_rect = ui.clip_rect();
     76 
     77             for contact_pubkey in self.contacts.iter() {
     78                 let (rect, resp) =
     79                     ui.allocate_exact_size(egui::vec2(ui.available_width(), 56.0), Sense::click());
     80 
     81                 if !clip_rect.intersects(rect) {
     82                     continue;
     83                 }
     84 
     85                 let profile = self
     86                     .ndb
     87                     .get_profile_by_pubkey(self.txn, contact_pubkey.bytes())
     88                     .ok();
     89 
     90                 let display_name = get_display_name(profile.as_ref());
     91                 let name_str = display_name.display_name.unwrap_or("Anonymous");
     92                 let profile_url = get_profile_url(profile.as_ref());
     93 
     94                 let resp = resp.on_hover_cursor(egui::CursorIcon::PointingHand);
     95 
     96                 if resp.hovered() {
     97                     ui.painter()
     98                         .rect_filled(rect, 0.0, ui.visuals().widgets.hovered.weak_bg_fill);
     99                 }
    100 
    101                 let mut child_ui = ui.new_child(egui::UiBuilder::new().max_rect(rect));
    102                 child_ui.horizontal(|ui| {
    103                     ui.add_space(16.0);
    104 
    105                     ui.add(&mut ProfilePic::new(self.img_cache, self.jobs, profile_url).size(48.0));
    106 
    107                     ui.add_space(12.0);
    108 
    109                     ui.add(
    110                         egui::Label::new(
    111                             RichText::new(name_str)
    112                                 .size(16.0)
    113                                 .color(ui.visuals().text_color()),
    114                         )
    115                         .selectable(false),
    116                     );
    117                 });
    118 
    119                 if resp.clicked() {
    120                     action = Some(ContactsListAction::Select(*contact_pubkey));
    121                 }
    122             }
    123         });
    124 
    125         DragResponse::output(action)
    126     }
    127 }