Leave the end flag to the thing that can see the end
A jump moved the list and then wrote down that the list was no longer at its newest line — which sounds like bookkeeping and is in fact a lie told early. `scrolled` is what sees where a scroll ended up, and it tells the client only when the answer CHANGES. Marked away from the end in advance, there was no change left for it to report: the list had moved, the client was never told, and it went on believing the reader was at the present. What that looks like is the jump button missing. A reader taken to a line three days back is not at the newest line and the way back to it is supposed to appear — and it did not, until they scrolled to the present by hand, which is the one thing the button exists to save them. So nothing is written down here. Where a jump lands is `scrolled`'s to report, and its report is what the client hears. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
e39a374 parent: b49f82a modified
crates/jolt-cosmic/src/lib.rs +10 -5 | @@ -557,7 +557,13 @@ impl App { | ||
| 557 | 557 | // and a jump that ends at the bottom of the room reads as a jump |
| 558 | 558 | // that did nothing. |
| 559 | 559 | if let Some(row) = ask.reveal { |
| 560 | - memo.at_end = false; | |
| 560 | + // The memo is not told where this lands. `scrolled` is what | |
| 561 | + // knows, and it tells the client only when the answer CHANGES | |
| 562 | + // — so a memo that marked itself away from the end here stole | |
| 563 | + // that change from it: the list moved, the client was never | |
| 564 | + // told, and it went on believing the reader was at the newest | |
| 565 | + // line. Which is a "jump to present" button that does not | |
| 566 | + // appear until the reader scrolls to the present by hand. | |
| 561 | 567 | tasks.push(reveal(ask.name.clone(), row, memo.height)); |
| 562 | 568 | } else if jumped || (ask.stick && memo.at_end) { |
| 563 | 569 | memo.at_end = true; |
| @@ -679,11 +685,10 @@ impl cosmic::Application for App { | ||
| 679 | 685 | let place = asking_row(&self.tree, &name) |
| 680 | 686 | .and_then(|row| placements(&name).get(row)); |
| 681 | 687 | if let Some((top, height)) = place { |
| 688 | + // Nothing written down here either, for the reason the | |
| 689 | + // commit path gives: where this ends up is `scrolled`'s to | |
| 690 | + // report, and its report is what the client hears. | |
| 682 | 691 | let y = centred_offset(top, height, viewport); |
| 683 | - if let Some(memo) = self.scrolls.get_mut(&name) { | |
| 684 | - memo.at_end = false; | |
| 685 | - memo.offset_y = y; | |
| 686 | - } | |
| 687 | 692 | return iced_scrollable::scroll_to( |
| 688 | 693 | scroll_id(&name), |
| 689 | 694 | AbsoluteOffset { x: None, y: Some(y) }, |
| @@ -557,7 +557,13 @@ impl App { | |||
| 557 | // and a jump that ends at the bottom of the room reads as a jump | 557 | // and a jump that ends at the bottom of the room reads as a jump |
| 558 | // that did nothing. | 558 | // that did nothing. |
| 559 | if let Some(row) = ask.reveal { | 559 | if let Some(row) = ask.reveal { |
| 560 | - memo.at_end = false; | 560 | + // The memo is not told where this lands. `scrolled` is what |
| 561 | + // knows, and it tells the client only when the answer CHANGES | ||
| 562 | + // — so a memo that marked itself away from the end here stole | ||
| 563 | + // that change from it: the list moved, the client was never | ||
| 564 | + // told, and it went on believing the reader was at the newest | ||
| 565 | + // line. Which is a "jump to present" button that does not | ||
| 566 | + // appear until the reader scrolls to the present by hand. | ||
| 561 | tasks.push(reveal(ask.name.clone(), row, memo.height)); | 567 | tasks.push(reveal(ask.name.clone(), row, memo.height)); |
| 562 | } else if jumped || (ask.stick && memo.at_end) { | 568 | } else if jumped || (ask.stick && memo.at_end) { |
| 563 | memo.at_end = true; | 569 | memo.at_end = true; |
| @@ -679,11 +685,10 @@ impl cosmic::Application for App { | |||
| 679 | let place = asking_row(&self.tree, &name) | 685 | let place = asking_row(&self.tree, &name) |
| 680 | .and_then(|row| placements(&name).get(row)); | 686 | .and_then(|row| placements(&name).get(row)); |
| 681 | if let Some((top, height)) = place { | 687 | if let Some((top, height)) = place { |
| 688 | + // Nothing written down here either, for the reason the | ||
| 689 | + // commit path gives: where this ends up is `scrolled`'s to | ||
| 690 | + // report, and its report is what the client hears. | ||
| 682 | let y = centred_offset(top, height, viewport); | 691 | let y = centred_offset(top, height, viewport); |
| 683 | - if let Some(memo) = self.scrolls.get_mut(&name) { | ||
| 684 | - memo.at_end = false; | ||
| 685 | - memo.offset_y = y; | ||
| 686 | - } | ||
| 687 | return iced_scrollable::scroll_to( | 692 | return iced_scrollable::scroll_to( |
| 688 | scroll_id(&name), | 693 | scroll_id(&name), |
| 689 | AbsoluteOffset { x: None, y: Some(y) }, | 694 | AbsoluteOffset { x: None, y: Some(y) }, |