notedeck

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

mentions_picker.rs (4621B)


      1 use egui::{vec2, Layout, ScrollArea, UiBuilder, Vec2b};
      2 use nostrdb::{Ndb, Transaction};
      3 use notedeck::{DragResponse, Images, Localization, MediaJobSender};
      4 use notedeck_ui::{profile_row, widgets::x_button, ProfileSearchResult};
      5 use tracing::error;
      6 
      7 /// Displays user profiles for the user to pick from.
      8 /// Useful for manually typing a username and selecting the profile desired
      9 pub struct MentionPickerView<'a> {
     10     ndb: &'a Ndb,
     11     txn: &'a Transaction,
     12     img_cache: &'a mut Images,
     13     results: &'a [ProfileSearchResult],
     14     jobs: &'a MediaJobSender,
     15     i18n: &'a mut Localization,
     16 }
     17 
     18 pub enum MentionPickerResponse {
     19     SelectResult(Option<usize>),
     20     DeleteMention,
     21 }
     22 
     23 impl<'a> MentionPickerView<'a> {
     24     pub fn new(
     25         img_cache: &'a mut Images,
     26         ndb: &'a Ndb,
     27         txn: &'a Transaction,
     28         results: &'a [ProfileSearchResult],
     29         jobs: &'a MediaJobSender,
     30         i18n: &'a mut Localization,
     31     ) -> Self {
     32         Self {
     33             ndb,
     34             txn,
     35             img_cache,
     36             results,
     37             jobs,
     38             i18n,
     39         }
     40     }
     41 
     42     fn show(&mut self, ui: &mut egui::Ui) -> MentionPickerResponse {
     43         let mut selection = None;
     44         ui.vertical(|ui| {
     45             for (i, res) in self.results.iter().enumerate() {
     46                 let profile = match self.ndb.get_profile_by_pubkey(self.txn, &res.pk) {
     47                     Ok(rec) => rec,
     48                     Err(e) => {
     49                         error!("Error fetching profile for pubkey {:?}: {e}", res.pk);
     50                         return;
     51                     }
     52                 };
     53 
     54                 if profile_row(
     55                     ui,
     56                     Some(&profile),
     57                     res.is_contact,
     58                     self.img_cache,
     59                     self.jobs,
     60                     self.i18n,
     61                 ) {
     62                     selection = Some(i)
     63                 }
     64             }
     65         });
     66 
     67         MentionPickerResponse::SelectResult(selection)
     68     }
     69 
     70     pub fn show_in_rect(
     71         &mut self,
     72         rect: egui::Rect,
     73         ui: &mut egui::Ui,
     74     ) -> DragResponse<MentionPickerResponse> {
     75         let widget_id = ui.id().with("mention_results");
     76         let area_resp = egui::Area::new(widget_id)
     77             .order(egui::Order::Foreground)
     78             .fixed_pos(rect.left_top())
     79             .constrain_to(rect)
     80             .show(ui.ctx(), |ui| {
     81                 let inner_margin_size = 8.0;
     82                 egui::Frame::NONE
     83                     .fill(ui.visuals().panel_fill)
     84                     .show(ui, |ui| {
     85                         ui.allocate_space(vec2(ui.available_width(), inner_margin_size));
     86                         let close_button_resp = {
     87                             let close_button_size = 16.0;
     88                             let width = rect.width() - (2.0 * inner_margin_size);
     89                             let (close_section_rect, _) = ui.allocate_exact_size(
     90                                 vec2(width, close_button_size),
     91                                 egui::Sense::hover(),
     92                             );
     93                             let (_, button_rect) = close_section_rect.split_left_right_at_x(
     94                                 close_section_rect.right() - close_button_size,
     95                             );
     96                             let button_resp = ui.allocate_rect(button_rect, egui::Sense::click());
     97                             ui.allocate_new_ui(
     98                                 UiBuilder::new()
     99                                     .max_rect(close_section_rect)
    100                                     .layout(Layout::right_to_left(egui::Align::Center)),
    101                                 |ui| ui.add(x_button(button_resp.rect)).clicked(),
    102                             )
    103                             .inner
    104                         };
    105 
    106                         ui.allocate_space(vec2(ui.available_width(), inner_margin_size));
    107 
    108                         let scroll_resp = ScrollArea::vertical()
    109                             .max_width(rect.width())
    110                             .auto_shrink(Vec2b::FALSE)
    111                             .show(ui, |ui| Some(self.show(ui)));
    112                         ui.advance_cursor_after_rect(rect);
    113 
    114                         DragResponse::scroll(scroll_resp).map_output(|o| {
    115                             if close_button_resp {
    116                                 MentionPickerResponse::DeleteMention
    117                             } else {
    118                                 o
    119                             }
    120                         })
    121                     })
    122                     .inner
    123             });
    124 
    125         area_resp.inner
    126     }
    127 }