notedeck

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

post.rs (5607B)


      1 use crate::app::Damus;
      2 use crate::draft::{Draft, DraftSource};
      3 use crate::post::NewPost;
      4 use crate::ui;
      5 use crate::ui::{Preview, PreviewConfig, View};
      6 use egui::widgets::text_edit::TextEdit;
      7 use nostrdb::Transaction;
      8 
      9 pub struct PostView<'app, 'd> {
     10     app: &'app mut Damus,
     11     /// account index
     12     poster: usize,
     13     draft_source: DraftSource<'d>,
     14     id_source: Option<egui::Id>,
     15 }
     16 
     17 pub enum PostAction {
     18     Post(NewPost),
     19 }
     20 
     21 pub struct PostResponse {
     22     pub action: Option<PostAction>,
     23     pub edit_response: egui::Response,
     24 }
     25 
     26 impl<'app, 'd> PostView<'app, 'd> {
     27     pub fn new(app: &'app mut Damus, draft_source: DraftSource<'d>, poster: usize) -> Self {
     28         let id_source: Option<egui::Id> = None;
     29         PostView {
     30             id_source,
     31             app,
     32             poster,
     33             draft_source,
     34         }
     35     }
     36 
     37     pub fn id_source(mut self, id_source: impl std::hash::Hash) -> Self {
     38         self.id_source = Some(egui::Id::new(id_source));
     39         self
     40     }
     41 
     42     fn draft(&mut self) -> &mut Draft {
     43         self.draft_source.draft(&mut self.app.drafts)
     44     }
     45 
     46     fn editbox(&mut self, txn: &nostrdb::Transaction, ui: &mut egui::Ui) -> egui::Response {
     47         ui.spacing_mut().item_spacing.x = 12.0;
     48 
     49         let pfp_size = 24.0;
     50 
     51         let poster_pubkey = self
     52             .app
     53             .account_manager
     54             .get_account(self.poster)
     55             .map(|acc| acc.pubkey.bytes())
     56             .unwrap_or(crate::test_data::test_pubkey());
     57 
     58         // TODO: refactor pfp control to do all of this for us
     59         let poster_pfp = self
     60             .app
     61             .ndb
     62             .get_profile_by_pubkey(txn, poster_pubkey)
     63             .as_ref()
     64             .ok()
     65             .and_then(|p| {
     66                 Some(ui::ProfilePic::from_profile(&mut self.app.img_cache, p)?.size(pfp_size))
     67             });
     68 
     69         if let Some(pfp) = poster_pfp {
     70             ui.add(pfp);
     71         } else {
     72             ui.add(
     73                 ui::ProfilePic::new(&mut self.app.img_cache, ui::ProfilePic::no_pfp_url())
     74                     .size(pfp_size),
     75             );
     76         }
     77 
     78         let buffer = &mut self.draft_source.draft(&mut self.app.drafts).buffer;
     79 
     80         let response = ui.add_sized(
     81             ui.available_size(),
     82             TextEdit::multiline(buffer)
     83                 .hint_text(egui::RichText::new("Write a banger note here...").weak())
     84                 .frame(false),
     85         );
     86 
     87         let focused = response.has_focus();
     88 
     89         ui.ctx().data_mut(|d| d.insert_temp(self.id(), focused));
     90 
     91         response
     92     }
     93 
     94     fn focused(&self, ui: &egui::Ui) -> bool {
     95         ui.ctx()
     96             .data(|d| d.get_temp::<bool>(self.id()).unwrap_or(false))
     97     }
     98 
     99     fn id(&self) -> egui::Id {
    100         self.id_source.unwrap_or_else(|| egui::Id::new("post"))
    101     }
    102 
    103     pub fn outer_margin() -> f32 {
    104         16.0
    105     }
    106 
    107     pub fn inner_margin() -> f32 {
    108         12.0
    109     }
    110 
    111     pub fn ui(&mut self, txn: &nostrdb::Transaction, ui: &mut egui::Ui) -> PostResponse {
    112         let focused = self.focused(ui);
    113         let stroke = if focused {
    114             ui.visuals().selection.stroke
    115         } else {
    116             //ui.visuals().selection.stroke
    117             ui.visuals().noninteractive().bg_stroke
    118         };
    119 
    120         let mut frame = egui::Frame::default()
    121             .inner_margin(egui::Margin::same(PostView::inner_margin()))
    122             .outer_margin(egui::Margin::same(PostView::outer_margin()))
    123             .fill(ui.visuals().extreme_bg_color)
    124             .stroke(stroke)
    125             .rounding(12.0);
    126 
    127         if focused {
    128             frame = frame.shadow(egui::epaint::Shadow {
    129                 offset: egui::vec2(0.0, 0.0),
    130                 blur: 8.0,
    131                 spread: 0.0,
    132                 color: stroke.color,
    133             });
    134         }
    135 
    136         frame
    137             .show(ui, |ui| {
    138                 ui.vertical(|ui| {
    139                     let edit_response = ui.horizontal(|ui| self.editbox(txn, ui)).inner;
    140 
    141                     let action = ui
    142                         .with_layout(egui::Layout::right_to_left(egui::Align::TOP), |ui| {
    143                             if ui
    144                                 .add_sized([91.0, 32.0], egui::Button::new("Post now"))
    145                                 .clicked()
    146                             {
    147                                 Some(PostAction::Post(NewPost {
    148                                     content: self.draft().buffer.clone(),
    149                                     account: self.poster,
    150                                 }))
    151                             } else {
    152                                 None
    153                             }
    154                         })
    155                         .inner;
    156 
    157                     PostResponse {
    158                         action,
    159                         edit_response,
    160                     }
    161                 })
    162                 .inner
    163             })
    164             .inner
    165     }
    166 }
    167 
    168 mod preview {
    169     use super::*;
    170     use crate::test_data;
    171 
    172     pub struct PostPreview {
    173         app: Damus,
    174     }
    175 
    176     impl PostPreview {
    177         fn new(is_mobile: bool) -> Self {
    178             PostPreview {
    179                 app: test_data::test_app(is_mobile),
    180             }
    181         }
    182     }
    183 
    184     impl View for PostPreview {
    185         fn ui(&mut self, ui: &mut egui::Ui) {
    186             let txn = Transaction::new(&self.app.ndb).unwrap();
    187             PostView::new(&mut self.app, DraftSource::Compose, 0).ui(&txn, ui);
    188         }
    189     }
    190 
    191     impl<'app, 'p> Preview for PostView<'app, 'p> {
    192         type Prev = PostPreview;
    193 
    194         fn preview(cfg: PreviewConfig) -> Self::Prev {
    195             PostPreview::new(cfg.is_mobile)
    196         }
    197     }
    198 }