commit db5e10656dfd8b71c21adadb5c2af7916290b2a2
parent 3cb2dd88b654ad0f064c7828897f4cf1394eab03
Author: kernelkind <kernelkind@gmail.com>
Date: Thu, 22 May 2025 20:05:11 -0400
set variable for scroll offset
necessary to maintain scroll positions across popup & Nav
Signed-off-by: kernelkind <kernelkind@gmail.com>
Diffstat:
3 files changed, 131 insertions(+), 105 deletions(-)
diff --git a/crates/notedeck_columns/src/ui/profile/mod.rs b/crates/notedeck_columns/src/ui/profile/mod.rs
@@ -65,67 +65,75 @@ impl<'a, 'd> ProfileView<'a, 'd> {
pub fn ui(&mut self, ui: &mut egui::Ui) -> Option<ProfileViewAction> {
let scroll_id = egui::Id::new(("profile_scroll", self.col_id, self.pubkey));
+ let offset_id = scroll_id.with("scroll_offset");
- ScrollArea::vertical()
- .id_salt(scroll_id)
- .show(ui, |ui| {
- let mut action = None;
- let txn = Transaction::new(self.note_context.ndb).expect("txn");
- if let Ok(profile) = self
- .note_context
- .ndb
- .get_profile_by_pubkey(&txn, self.pubkey.bytes())
- {
- if self.profile_body(ui, profile) {
- action = Some(ProfileViewAction::EditProfile);
- }
+ let mut scroll_area = ScrollArea::vertical().id_salt(scroll_id);
+
+ if let Some(offset) = ui.data(|i| i.get_temp::<f32>(offset_id)) {
+ scroll_area = scroll_area.vertical_scroll_offset(offset);
+ }
+
+ let output = scroll_area.show(ui, |ui| {
+ let mut action = None;
+ let txn = Transaction::new(self.note_context.ndb).expect("txn");
+ if let Ok(profile) = self
+ .note_context
+ .ndb
+ .get_profile_by_pubkey(&txn, self.pubkey.bytes())
+ {
+ if self.profile_body(ui, profile) {
+ action = Some(ProfileViewAction::EditProfile);
}
- let profile_timeline = self
- .timeline_cache
- .notes(
- self.note_context.ndb,
- self.note_context.note_cache,
- &txn,
- &TimelineKind::Profile(*self.pubkey),
- )
- .get_ptr();
-
- profile_timeline.selected_view =
- tabs_ui(ui, profile_timeline.selected_view, &profile_timeline.views);
-
- let reversed = false;
- // poll for new notes and insert them into our existing notes
- if let Err(e) = profile_timeline.poll_notes_into_view(
+ }
+ let profile_timeline = self
+ .timeline_cache
+ .notes(
self.note_context.ndb,
- &txn,
- self.unknown_ids,
self.note_context.note_cache,
- reversed,
- ) {
- error!("Profile::poll_notes_into_view: {e}");
- }
-
- if let Some(note_action) = TimelineTabView::new(
- profile_timeline.current_view(),
- reversed,
- self.note_options,
&txn,
- self.is_muted,
- self.note_context,
- &self
- .accounts
- .get_selected_account()
- .map(|a| (&a.key).into()),
- self.jobs,
+ &TimelineKind::Profile(*self.pubkey),
)
- .show(ui)
- {
- action = Some(ProfileViewAction::Note(note_action));
- }
+ .get_ptr();
+
+ profile_timeline.selected_view =
+ tabs_ui(ui, profile_timeline.selected_view, &profile_timeline.views);
+
+ let reversed = false;
+ // poll for new notes and insert them into our existing notes
+ if let Err(e) = profile_timeline.poll_notes_into_view(
+ self.note_context.ndb,
+ &txn,
+ self.unknown_ids,
+ self.note_context.note_cache,
+ reversed,
+ ) {
+ error!("Profile::poll_notes_into_view: {e}");
+ }
+
+ if let Some(note_action) = TimelineTabView::new(
+ profile_timeline.current_view(),
+ reversed,
+ self.note_options,
+ &txn,
+ self.is_muted,
+ self.note_context,
+ &self
+ .accounts
+ .get_selected_account()
+ .map(|a| (&a.key).into()),
+ self.jobs,
+ )
+ .show(ui)
+ {
+ action = Some(ProfileViewAction::Note(note_action));
+ }
+
+ action
+ });
+
+ ui.data_mut(|d| d.insert_temp(offset_id, output.state.offset.y));
- action
- })
- .inner
+ output.inner
}
fn profile_body(&mut self, ui: &mut egui::Ui, profile: ProfileRecord<'_>) -> bool {
diff --git a/crates/notedeck_columns/src/ui/thread.rs b/crates/notedeck_columns/src/ui/thread.rs
@@ -54,62 +54,72 @@ impl<'a, 'd> ThreadView<'a, 'd> {
pub fn ui(&mut self, ui: &mut egui::Ui) -> Option<NoteAction> {
let txn = Transaction::new(self.note_context.ndb).expect("txn");
- egui::ScrollArea::vertical()
+ let mut scroll_area = egui::ScrollArea::vertical()
.id_salt(self.id_source)
.animated(false)
.auto_shrink([false, false])
- .scroll_bar_visibility(egui::scroll_area::ScrollBarVisibility::AlwaysVisible)
- .show(ui, |ui| {
- let root_id = match RootNoteId::new(
- self.note_context.ndb,
- self.note_context.note_cache,
- &txn,
- self.selected_note_id,
- ) {
- Ok(root_id) => root_id,
-
- Err(err) => {
- ui.label(format!("Error loading thread: {:?}", err));
- return None;
- }
- };
-
- let thread_timeline = self
- .timeline_cache
- .notes(
- self.note_context.ndb,
- self.note_context.note_cache,
- &txn,
- &TimelineKind::Thread(ThreadSelection::from_root_id(root_id.to_owned())),
- )
- .get_ptr();
-
- // TODO(jb55): skip poll if ThreadResult is fresh?
-
- let reversed = true;
- // poll for new notes and insert them into our existing notes
- if let Err(err) = thread_timeline.poll_notes_into_view(
- self.note_context.ndb,
- &txn,
- self.unknown_ids,
- self.note_context.note_cache,
- reversed,
- ) {
- error!("error polling notes into thread timeline: {err}");
+ .scroll_bar_visibility(egui::scroll_area::ScrollBarVisibility::AlwaysVisible);
+
+ let offset_id = self.id_source.with("scroll_offset");
+
+ if let Some(offset) = ui.data(|i| i.get_temp::<f32>(offset_id)) {
+ scroll_area = scroll_area.vertical_scroll_offset(offset);
+ }
+
+ let output = scroll_area.show(ui, |ui| {
+ let root_id = match RootNoteId::new(
+ self.note_context.ndb,
+ self.note_context.note_cache,
+ &txn,
+ self.selected_note_id,
+ ) {
+ Ok(root_id) => root_id,
+
+ Err(err) => {
+ ui.label(format!("Error loading thread: {:?}", err));
+ return None;
}
+ };
- TimelineTabView::new(
- thread_timeline.current_view(),
- true,
- self.note_options,
+ let thread_timeline = self
+ .timeline_cache
+ .notes(
+ self.note_context.ndb,
+ self.note_context.note_cache,
&txn,
- self.is_muted,
- self.note_context,
- self.cur_acc,
- self.jobs,
+ &TimelineKind::Thread(ThreadSelection::from_root_id(root_id.to_owned())),
)
- .show(ui)
- })
- .inner
+ .get_ptr();
+
+ // TODO(jb55): skip poll if ThreadResult is fresh?
+
+ let reversed = true;
+ // poll for new notes and insert them into our existing notes
+ if let Err(err) = thread_timeline.poll_notes_into_view(
+ self.note_context.ndb,
+ &txn,
+ self.unknown_ids,
+ self.note_context.note_cache,
+ reversed,
+ ) {
+ error!("error polling notes into thread timeline: {err}");
+ }
+
+ TimelineTabView::new(
+ thread_timeline.current_view(),
+ true,
+ self.note_options,
+ &txn,
+ self.is_muted,
+ self.note_context,
+ self.cur_acc,
+ self.jobs,
+ )
+ .show(ui)
+ });
+
+ ui.data_mut(|d| d.insert_temp(offset_id, output.state.offset.y));
+
+ output.inner
}
}
diff --git a/crates/notedeck_columns/src/ui/timeline.rs b/crates/notedeck_columns/src/ui/timeline.rs
@@ -130,6 +130,12 @@ fn timeline_ui(
.auto_shrink([false, false])
.scroll_bar_visibility(ScrollBarVisibility::AlwaysVisible);
+ let offset_id = scroll_id.with("timeline_scroll_offset");
+
+ if let Some(offset) = ui.data(|i| i.get_temp::<f32>(offset_id)) {
+ scroll_area = scroll_area.vertical_scroll_offset(offset);
+ }
+
if let Some(goto_top_resp) = goto_top_resp {
if goto_top_resp.clicked() {
scroll_area = scroll_area.vertical_scroll_offset(0.0);
@@ -163,6 +169,8 @@ fn timeline_ui(
.show(ui)
});
+ ui.data_mut(|d| d.insert_temp(offset_id, scroll_output.state.offset.y));
+
let at_top_after_scroll = scroll_output.state.offset.y == 0.0;
let cur_show_top_button = ui.ctx().data(|d| d.get_temp::<bool>(show_top_button_id));
@@ -362,9 +370,9 @@ impl<'a, 'd> TimelineTabView<'a, 'd> {
let len = self.tab.notes.len();
let is_muted = self.is_muted;
+
self.tab
.list
- .clone()
.borrow_mut()
.ui_custom_layout(ui, len, |ui, start_index| {
ui.spacing_mut().item_spacing.y = 0.0;