notedeck

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

commit 0bc32272d2ab7cafc398681f93025ff819b41070
parent b05d39cc81b2ca9c8b27935836f12467e4b84d3e
Author: kernelkind <kernelkind@gmail.com>
Date:   Wed, 23 Jul 2025 21:01:38 -0600

refactor scrolling for post, reply & quote views

Signed-off-by: kernelkind <kernelkind@gmail.com>

Diffstat:
Mcrates/notedeck_columns/src/nav.rs | 55++++++++++++++++++++++---------------------------------
Mcrates/notedeck_columns/src/ui/note/post.rs | 28++++++++++++++++------------
Mcrates/notedeck_columns/src/ui/note/quote_repost.rs | 36++++++++++++++++++++----------------
Mcrates/notedeck_columns/src/ui/note/reply.rs | 30+++++++++++++++++-------------
4 files changed, 75 insertions(+), 74 deletions(-)

diff --git a/crates/notedeck_columns/src/nav.rs b/crates/notedeck_columns/src/nav.rs @@ -631,27 +631,22 @@ fn render_nav_body( return None; }; - let id = egui::Id::new(("post", col, note.key().unwrap())); let poster = ctx.accounts.selected_filled()?; let action = { let draft = app.drafts.reply_mut(note.id()); - let response = egui::ScrollArea::vertical() - .show(ui, |ui| { - ui::PostReplyView::new( - &mut note_context, - poster, - draft, - &note, - inner_rect, - app.note_options, - &mut app.jobs, - ) - .id_source(id) - .show(ui) - }) - .inner; + let response = ui::PostReplyView::new( + &mut note_context, + poster, + draft, + &note, + inner_rect, + app.note_options, + &mut app.jobs, + col, + ) + .show(ui); response.action }; @@ -672,26 +667,20 @@ fn render_nav_body( return None; }; - let id = egui::Id::new(("post", col, note.key().unwrap())); - let poster = ctx.accounts.selected_filled()?; let draft = app.drafts.quote_mut(note.id()); - let response = egui::ScrollArea::vertical() - .show(ui, |ui| { - crate::ui::note::QuoteRepostView::new( - &mut note_context, - poster, - draft, - &note, - inner_rect, - app.note_options, - &mut app.jobs, - ) - .id_source(id) - .show(ui) - }) - .inner; + let response = crate::ui::note::QuoteRepostView::new( + &mut note_context, + poster, + draft, + &note, + inner_rect, + app.note_options, + &mut app.jobs, + col, + ) + .show(ui); response.action.map(Into::into) } diff --git a/crates/notedeck_columns/src/ui/note/post.rs b/crates/notedeck_columns/src/ui/note/post.rs @@ -35,7 +35,6 @@ pub struct PostView<'a, 'd> { draft: &'a mut Draft, post_type: PostType, poster: FilledKeypair<'a>, - id_source: Option<egui::Id>, inner_rect: egui::Rect, note_options: NoteOptions, jobs: &'a mut JobsCache, @@ -112,12 +111,10 @@ impl<'a, 'd> PostView<'a, 'd> { note_options: NoteOptions, jobs: &'a mut JobsCache, ) -> Self { - let id_source: Option<egui::Id> = None; PostView { note_context, draft, poster, - id_source, post_type, inner_rect, note_options, @@ -125,9 +122,12 @@ impl<'a, 'd> PostView<'a, 'd> { } } - pub fn id_source(mut self, id_source: impl std::hash::Hash) -> Self { - self.id_source = Some(egui::Id::new(id_source)); - self + fn id() -> egui::Id { + egui::Id::new("post") + } + + pub fn scroll_id() -> egui::Id { + PostView::id().with("scroll") } fn editbox(&mut self, txn: &nostrdb::Transaction, ui: &mut egui::Ui) -> egui::Response { @@ -213,7 +213,8 @@ impl<'a, 'd> PostView<'a, 'd> { let focused = out.response.has_focus(); - ui.ctx().data_mut(|d| d.insert_temp(self.id(), focused)); + ui.ctx() + .data_mut(|d| d.insert_temp(PostView::id(), focused)); out.response } @@ -305,11 +306,7 @@ impl<'a, 'd> PostView<'a, 'd> { fn focused(&self, ui: &egui::Ui) -> bool { ui.ctx() - .data(|d| d.get_temp::<bool>(self.id()).unwrap_or(false)) - } - - fn id(&self) -> egui::Id { - self.id_source.unwrap_or_else(|| egui::Id::new("post")) + .data(|d| d.get_temp::<bool>(PostView::id()).unwrap_or(false)) } pub fn outer_margin() -> i8 { @@ -321,6 +318,13 @@ impl<'a, 'd> PostView<'a, 'd> { } pub fn ui(&mut self, txn: &Transaction, ui: &mut egui::Ui) -> PostResponse { + ScrollArea::vertical() + .id_salt(PostView::scroll_id()) + .show(ui, |ui| self.ui_no_scroll(txn, ui)) + .inner + } + + pub fn ui_no_scroll(&mut self, txn: &Transaction, ui: &mut egui::Ui) -> PostResponse { let focused = self.focused(ui); let stroke = if focused { ui.visuals().selection.stroke diff --git a/crates/notedeck_columns/src/ui/note/quote_repost.rs b/crates/notedeck_columns/src/ui/note/quote_repost.rs @@ -4,6 +4,7 @@ use crate::{ ui::{self}, }; +use egui::ScrollArea; use enostr::{FilledKeypair, NoteId}; use notedeck::NoteContext; use notedeck_ui::{jobs::JobsCache, NoteOptions}; @@ -13,7 +14,7 @@ pub struct QuoteRepostView<'a, 'd> { poster: FilledKeypair<'a>, draft: &'a mut Draft, quoting_note: &'a nostrdb::Note<'a>, - id_source: Option<egui::Id>, + scroll_id: egui::Id, inner_rect: egui::Rect, note_options: NoteOptions, jobs: &'a mut JobsCache, @@ -29,22 +30,36 @@ impl<'a, 'd> QuoteRepostView<'a, 'd> { inner_rect: egui::Rect, note_options: NoteOptions, jobs: &'a mut JobsCache, + col: usize, ) -> Self { - let id_source: Option<egui::Id> = None; QuoteRepostView { note_context, poster, draft, quoting_note, - id_source, + scroll_id: QuoteRepostView::scroll_id(col, quoting_note.id()), inner_rect, note_options, jobs, } } + fn id(col: usize, note_id: &[u8; 32]) -> egui::Id { + egui::Id::new(("quote_repost", col, note_id)) + } + + pub fn scroll_id(col: usize, note_id: &[u8; 32]) -> egui::Id { + QuoteRepostView::id(col, note_id).with("scroll") + } + pub fn show(&mut self, ui: &mut egui::Ui) -> PostResponse { - let id = self.id(); + ScrollArea::vertical() + .id_salt(self.scroll_id) + .show(ui, |ui| self.show_internal(ui)) + .inner + } + + fn show_internal(&mut self, ui: &mut egui::Ui) -> PostResponse { let quoting_note_id = self.quoting_note.id(); let post_resp = ui::PostView::new( @@ -56,18 +71,7 @@ impl<'a, 'd> QuoteRepostView<'a, 'd> { self.note_options, self.jobs, ) - .id_source(id) - .ui(self.quoting_note.txn().unwrap(), ui); + .ui_no_scroll(self.quoting_note.txn().unwrap(), ui); post_resp } - - pub fn id_source(mut self, id: egui::Id) -> Self { - self.id_source = Some(id); - self - } - - pub fn id(&self) -> egui::Id { - self.id_source - .unwrap_or_else(|| egui::Id::new("quote-repost-view")) - } } diff --git a/crates/notedeck_columns/src/ui/note/reply.rs b/crates/notedeck_columns/src/ui/note/reply.rs @@ -4,7 +4,7 @@ use crate::ui::{ note::{PostAction, PostResponse, PostType}, }; -use egui::{Rect, Response, Ui}; +use egui::{Rect, Response, ScrollArea, Ui}; use enostr::{FilledKeypair, NoteId}; use notedeck::NoteContext; use notedeck_ui::jobs::JobsCache; @@ -15,7 +15,7 @@ pub struct PostReplyView<'a, 'd> { poster: FilledKeypair<'a>, draft: &'a mut Draft, note: &'a nostrdb::Note<'a>, - id_source: Option<egui::Id>, + scroll_id: egui::Id, inner_rect: egui::Rect, note_options: NoteOptions, jobs: &'a mut JobsCache, @@ -31,31 +31,37 @@ impl<'a, 'd> PostReplyView<'a, 'd> { inner_rect: egui::Rect, note_options: NoteOptions, jobs: &'a mut JobsCache, + col: usize, ) -> Self { - let id_source: Option<egui::Id> = None; PostReplyView { note_context, poster, draft, note, - id_source, + scroll_id: PostReplyView::scroll_id(col, note.id()), inner_rect, note_options, jobs, } } - pub fn id_source(mut self, id: egui::Id) -> Self { - self.id_source = Some(id); - self + fn id(col: usize, note_id: &[u8; 32]) -> egui::Id { + egui::Id::new(("reply_view", col, note_id)) } - pub fn id(&self) -> egui::Id { - self.id_source - .unwrap_or_else(|| egui::Id::new("post-reply-view")) + pub fn scroll_id(col: usize, note_id: &[u8; 32]) -> egui::Id { + PostReplyView::id(col, note_id).with("scroll") } pub fn show(&mut self, ui: &mut egui::Ui) -> PostResponse { + ScrollArea::vertical() + .id_salt(self.scroll_id) + .show(ui, |ui| self.show_internal(ui)) + .inner + } + + // no scroll + fn show_internal(&mut self, ui: &mut egui::Ui) -> PostResponse { ui.vertical(|ui| { let avail_rect = ui.available_rect_before_wrap(); @@ -81,7 +87,6 @@ impl<'a, 'd> PostReplyView<'a, 'd> { }) .inner; - let id = self.id(); let replying_to = self.note.id(); let rect_before_post = ui.min_rect(); @@ -95,8 +100,7 @@ impl<'a, 'd> PostReplyView<'a, 'd> { self.note_options, self.jobs, ) - .id_source(id) - .ui(self.note.txn().unwrap(), ui) + .ui_no_scroll(self.note.txn().unwrap(), ui) }; post_response.action = post_response