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