notedeck

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

create_convo.rs (4791B)


      1 use egui::{Label, RichText};
      2 use enostr::Pubkey;
      3 use nostrdb::{Ndb, Transaction};
      4 use notedeck::{tr, ContactState, Images, Localization, MediaJobSender, NotedeckTextStyle};
      5 use notedeck_ui::{
      6     profile_row, search_input_box, search_profiles, ContactsListView, ProfileSearchResult,
      7 };
      8 
      9 use crate::cache::CreateConvoState;
     10 
     11 pub struct CreateConvoUi<'a> {
     12     ndb: &'a Ndb,
     13     jobs: &'a MediaJobSender,
     14     img_cache: &'a mut Images,
     15     contacts: &'a ContactState,
     16     i18n: &'a mut Localization,
     17     state: &'a mut CreateConvoState,
     18 }
     19 
     20 pub struct CreateConvoResponse {
     21     pub recipient: Pubkey,
     22 }
     23 
     24 impl<'a> CreateConvoUi<'a> {
     25     pub fn new(
     26         ndb: &'a Ndb,
     27         jobs: &'a MediaJobSender,
     28         img_cache: &'a mut Images,
     29         contacts: &'a ContactState,
     30         i18n: &'a mut Localization,
     31         state: &'a mut CreateConvoState,
     32     ) -> Self {
     33         Self {
     34             ndb,
     35             jobs,
     36             img_cache,
     37             contacts,
     38             i18n,
     39             state,
     40         }
     41     }
     42 
     43     pub fn ui(&mut self, ui: &mut egui::Ui) -> Option<CreateConvoResponse> {
     44         let txn = Transaction::new(self.ndb).expect("txn");
     45 
     46         // Search input
     47         ui.add_space(8.0);
     48         let hint = tr!(
     49             self.i18n,
     50             "Search profiles...",
     51             "Placeholder for profile search input"
     52         );
     53         ui.add(search_input_box(&mut self.state.query, &hint));
     54         ui.add_space(12.0);
     55 
     56         let query = self.state.query.trim();
     57 
     58         if query.is_empty() {
     59             // Show contacts list when not searching
     60             ui.add(Label::new(
     61                 RichText::new(tr!(
     62                     self.i18n,
     63                     "Contacts",
     64                     "Heading shown when choosing a contact to start a new chat"
     65                 ))
     66                 .text_style(NotedeckTextStyle::Heading.text_style()),
     67             ));
     68 
     69             if let ContactState::Received { contacts, .. } = self.contacts {
     70                 let resp = ContactsListView::new(
     71                     contacts,
     72                     self.jobs,
     73                     self.ndb,
     74                     self.img_cache,
     75                     &txn,
     76                     self.i18n,
     77                 )
     78                 .ui(ui);
     79 
     80                 resp.output.map(|a| match a {
     81                     notedeck_ui::ContactsListAction::Select(pubkey) => {
     82                         CreateConvoResponse { recipient: pubkey }
     83                     }
     84                 })
     85             } else {
     86                 // No contacts yet
     87                 ui.label(tr!(
     88                     self.i18n,
     89                     "No contacts yet",
     90                     "Shown when user has no contacts to display"
     91                 ));
     92                 None
     93             }
     94         } else {
     95             // Show search results
     96             ui.add(Label::new(
     97                 RichText::new(tr!(
     98                     self.i18n,
     99                     "Results",
    100                     "Heading shown above search results"
    101                 ))
    102                 .text_style(NotedeckTextStyle::Heading.text_style()),
    103             ));
    104 
    105             let results = search_profiles(self.ndb, &txn, query, self.contacts, 128);
    106 
    107             if results.is_empty() {
    108                 ui.add_space(20.0);
    109                 ui.label(
    110                     RichText::new(tr!(
    111                         self.i18n,
    112                         "No profiles found",
    113                         "Shown when profile search returns no results"
    114                     ))
    115                     .weak(),
    116                 );
    117                 None
    118             } else {
    119                 search_results_list(
    120                     ui,
    121                     &results,
    122                     self.ndb,
    123                     &txn,
    124                     self.img_cache,
    125                     self.jobs,
    126                     self.i18n,
    127                 )
    128             }
    129         }
    130     }
    131 }
    132 
    133 /// Renders a scrollable list of search results. Returns `Some(CreateConvoResponse)`
    134 /// if the user selects a profile.
    135 fn search_results_list(
    136     ui: &mut egui::Ui,
    137     results: &[ProfileSearchResult],
    138     ndb: &Ndb,
    139     txn: &Transaction,
    140     img_cache: &mut Images,
    141     jobs: &MediaJobSender,
    142     i18n: &mut Localization,
    143 ) -> Option<CreateConvoResponse> {
    144     let mut action = None;
    145 
    146     egui::ScrollArea::vertical().show(ui, |ui| {
    147         for result in results {
    148             let profile = ndb.get_profile_by_pubkey(txn, &result.pk).ok();
    149 
    150             if profile_row(
    151                 ui,
    152                 profile.as_ref(),
    153                 result.is_contact,
    154                 img_cache,
    155                 jobs,
    156                 i18n,
    157             ) {
    158                 action = Some(CreateConvoResponse {
    159                     recipient: Pubkey::new(result.pk),
    160                 });
    161             }
    162         }
    163     });
    164 
    165     action
    166 }