Preserve rename preview scroll through full details

This commit is contained in:
2026-09-13 02:27:04 -07:00
parent 357da24542
commit 022d8cda2a
2 changed files with 159 additions and 6 deletions
+38 -3
View File
@@ -49,6 +49,7 @@ pub enum Event {
Line(Id, Id, bool),
Segment(Id, Id, bool),
Details(Id, bool),
PreviewScrolled(Id, Id, Id, f32),
DetailSegment(Id, bool),
ReadOnly(Id, text_editor::Action),
Undo(Id),
@@ -112,6 +113,7 @@ struct Form {
line: usize,
segment: usize,
preview_destination: Id,
preview_offset: f32,
details: bool,
detail_segment: usize,
detail_editor: text_editor::Content,
@@ -170,6 +172,17 @@ impl App {
return false;
};
match event {
Event::PreviewScrolled(invocation, approval, destination, offset) => {
*invocation == form.invocation
&& !form.details
&& form
.approval
.as_ref()
.is_some_and(|ready| ready.id == *approval)
&& *destination == form.preview_destination
&& offset.is_finite()
&& *offset >= 0.
}
Event::Preview(invocation, generation) => {
*invocation == form.invocation && *generation == form.generation
}
@@ -435,11 +448,23 @@ impl App {
}
form.details = value;
// Leaving or returning to the preview ends the old visit. Keep
// its selected page and retained scroll; only retire delayed
// operations, without scheduling another return-to-top.
// its selected page and scroll; the Details widget replaces the
// preview subtree, so restore the reported offset on return.
form.preview_destination = Id::new_v4();
form.detail_segment = 0;
refresh_details(form);
if !value && let Some(ready) = &form.approval {
return iced::widget::operation::scroll_to(
preview_scroll_id(form, ready.id),
iced::widget::scrollable::AbsoluteOffset {
x: None,
y: Some(form.preview_offset),
},
);
}
}
Event::PreviewScrolled(_, _, _, offset) => {
self.source_rename.form.as_mut().unwrap().preview_offset = offset;
}
Event::DetailSegment(_, next) => {
let form = self.source_rename.form.as_mut().unwrap();
@@ -516,6 +541,7 @@ impl App {
line: 0,
segment: 0,
preview_destination: Id::new_v4(),
preview_offset: 0.,
details: false,
detail_segment: 0,
detail_editor: text_editor::Content::new(),
@@ -953,6 +979,7 @@ fn input_id(invocation: Id) -> iced::widget::Id {
// or changing a filter that leaves the page tuple unchanged (the ABA case).
fn reset_preview_position(form: &mut Form) -> Task<Message> {
form.preview_destination = Id::new_v4();
form.preview_offset = 0.;
if !form.details
&& let Some(ready) = &form.approval
{
@@ -1118,7 +1145,15 @@ where
pager(format!("Row segments {}/{} · both sides", form.segment + 1, segments.max(1)),
(form.segment > 0).then(|| message(Event::Segment(invocation, preview_id, false))),
(form.segment + 1 < segments).then(|| message(Event::Segment(invocation, preview_id, true)))),
scrollable(displayed).id(preview_scroll_id(form, preview_id)).height(Fill).width(Fill).spacing(8),
scrollable(displayed)
.id(preview_scroll_id(form, preview_id))
.on_scroll({
let destination = form.preview_destination;
move |viewport| message(Event::PreviewScrolled(
invocation, preview_id, destination, viewport.absolute_offset().y,
))
})
.height(Fill).width(Fill).spacing(8),
].spacing(6).height(Fill).into()
} else {
scrollable(column![