reply.rs (5557B)
1 use crate::draft::Draft; 2 use crate::ui::{ 3 self, 4 note::{PostAction, PostResponse, PostType}, 5 }; 6 7 use egui::{Rect, Response, ScrollArea, Ui}; 8 use enostr::{FilledKeypair, NoteId}; 9 use notedeck::{JobsCache, NoteContext}; 10 use notedeck_ui::{NoteOptions, NoteView, ProfilePic}; 11 12 pub struct PostReplyView<'a, 'd> { 13 note_context: &'a mut NoteContext<'d>, 14 poster: FilledKeypair<'a>, 15 draft: &'a mut Draft, 16 note: &'a nostrdb::Note<'a>, 17 scroll_id: egui::Id, 18 inner_rect: egui::Rect, 19 note_options: NoteOptions, 20 jobs: &'a mut JobsCache, 21 } 22 23 impl<'a, 'd> PostReplyView<'a, 'd> { 24 #[allow(clippy::too_many_arguments)] 25 pub fn new( 26 note_context: &'a mut NoteContext<'d>, 27 poster: FilledKeypair<'a>, 28 draft: &'a mut Draft, 29 note: &'a nostrdb::Note<'a>, 30 inner_rect: egui::Rect, 31 note_options: NoteOptions, 32 jobs: &'a mut JobsCache, 33 col: usize, 34 ) -> Self { 35 PostReplyView { 36 note_context, 37 poster, 38 draft, 39 note, 40 scroll_id: PostReplyView::scroll_id(col, note.id()), 41 inner_rect, 42 note_options, 43 jobs, 44 } 45 } 46 47 fn id(col: usize, note_id: &[u8; 32]) -> egui::Id { 48 egui::Id::new(("reply_view", col, note_id)) 49 } 50 51 pub fn scroll_id(col: usize, note_id: &[u8; 32]) -> egui::Id { 52 PostReplyView::id(col, note_id).with("scroll") 53 } 54 55 pub fn show(&mut self, ui: &mut egui::Ui) -> PostResponse { 56 ScrollArea::vertical() 57 .id_salt(self.scroll_id) 58 .show(ui, |ui| self.show_internal(ui)) 59 .inner 60 } 61 62 // no scroll 63 fn show_internal(&mut self, ui: &mut egui::Ui) -> PostResponse { 64 ui.vertical(|ui| { 65 let avail_rect = ui.available_rect_before_wrap(); 66 67 // This is the offset of the post view's pfp. We use this 68 // to indent things so that the reply line is aligned 69 let pfp_offset: i8 = ui::PostView::outer_margin() 70 + ui::PostView::inner_margin() 71 + ProfilePic::small_size() / 2; 72 73 let note_offset: i8 = 74 pfp_offset - ProfilePic::medium_size() / 2 - NoteView::expand_size() / 2; 75 76 let quoted_note = egui::Frame::NONE 77 .outer_margin(egui::Margin::same(note_offset)) 78 .show(ui, |ui| { 79 NoteView::new(self.note_context, self.note, self.note_options, self.jobs) 80 .truncate(false) 81 .selectable_text(true) 82 .actionbar(false) 83 .medium_pfp(true) 84 .options_button(true) 85 .show(ui) 86 }) 87 .inner; 88 89 let replying_to = self.note.id(); 90 let rect_before_post = ui.min_rect(); 91 92 let mut post_response = { 93 ui::PostView::new( 94 self.note_context, 95 self.draft, 96 PostType::Reply(NoteId::new(*replying_to)), 97 self.poster, 98 self.inner_rect, 99 self.note_options, 100 self.jobs, 101 ) 102 .ui_no_scroll(self.note.txn().unwrap(), ui) 103 }; 104 105 post_response.action = post_response 106 .action 107 .or(quoted_note.action.map(PostAction::QuotedNoteAction)); 108 109 reply_line_ui( 110 &rect_before_post, 111 &post_response.edit_response, 112 pfp_offset as f32, 113 &avail_rect, 114 ui, 115 ); 116 117 // 118 // NOTE(jb55): We add some space so that you can scroll to 119 // put the input box higher. This can happen in some 120 // situations where the input box gets covered or if its too 121 // large and things start breaking. I think this is an ok 122 // solution but there could be a better one. 123 // 124 ui.add_space(500.0); 125 126 post_response 127 }) 128 .inner 129 } 130 } 131 132 /// The vertical line in the reply view 133 fn reply_line_ui( 134 rect_before_post: &Rect, 135 edit_response: &Response, 136 pfp_offset: f32, 137 avail_rect: &Rect, 138 ui: &mut Ui, 139 ) { 140 // Position and draw the reply line 141 let mut rect = ui.min_rect(); 142 143 // Position the line right above the poster's profile pic in 144 // the post box. Use the PostView's margin values to 145 // determine this offset. 146 rect.min.x = avail_rect.min.x + pfp_offset; 147 148 // honestly don't know what the fuck I'm doing here. just trying 149 // to get the line under the profile picture 150 rect.min.y = avail_rect.min.y 151 + (ProfilePic::medium_size() as f32 / 2.0 152 + ProfilePic::medium_size() as f32 153 + NoteView::expand_size() as f32 * 2.0) 154 + 1.0; 155 156 // For some reason we need to nudge the reply line's height a 157 // few more pixels? 158 let nudge = if edit_response.has_focus() { 159 // we nudge by one less pixel if focused, otherwise it 160 // overlaps the focused PostView purple border color 161 2.0 162 } else { 163 // we have to nudge by one more pixel when not focused 164 // otherwise it looks like there's a gap(?) 165 3.0 166 }; 167 168 rect.max.y = rect_before_post.max.y + ui::PostView::outer_margin() as f32 + nudge; 169 170 ui.painter().vline( 171 rect.left(), 172 rect.y_range(), 173 ui.visuals().widgets.noninteractive.bg_stroke, 174 ); 175 }