Stretch the whole file at the ends, not one line
`Modifier.horizontalScroll` builds its own overscroll effect per node, so with a node per row only the line under the finger bent when the file was dragged past either end and the rest sat still beside it -- the same complaint as the offsets, one layer out. There is an overload that takes the effect instead of making one, and it leaves the rendering to the caller. So the viewer makes one effect, hands it to every row, and renders it once on a box around the list: the file bends as the block it scrolls as. This only works now that every row is the same width -- rows that disagreed about where the end was would disagree about when to stretch. **Not seen working.** Measured on the emulator here: over-dragging well past the end and capturing mid-gesture produces a frame with no stretch in it at all, and the list's own vertical overscroll does not appear either, so this VM cannot show the effect for any scrollable. Noted in ~/.claude/MACHINE.md so the next session does not spend the same half hour on it. What was checked here is everything either side: the scroll still reaches both ends, the position survives scrolling vertically, and nothing else moved. The stretch itself wants a look on the phone. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
457907087c
commit
7b08a71e64
2 files changed
+41
-13
No files matched your search
@@ -1,13 +1,16 @@
|
||||
package com.example.aiapp
|
||||
|
||||
import androidx.compose.foundation.horizontalScroll
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.overscroll
|
||||
import androidx.compose.foundation.rememberOverscrollEffect
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.text.selection.SelectionContainer
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
@@ -21,6 +24,7 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clipToBounds
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
@@ -85,6 +89,14 @@ fun ScannedFile(content: String, language: Language?, modifier: Modifier = Modif
|
||||
* as the block this comment always claimed it was. Reported by Iris on 2026-09-04 as "it seems to
|
||||
* affect different rows differently", which is exactly what a per-row range looks like.
|
||||
*
|
||||
* The stretch at the ends of the travel is **one** effect for the whole file, rendered on the box
|
||||
* around the list rather than by each row. `horizontalScroll` makes its own per node otherwise, so
|
||||
* only the line under the finger stretched and the rest of the file sat still beside it -- the same
|
||||
* complaint as the offsets above, one layer further out. Handing every row the same effect and
|
||||
* rendering it once is what makes the file bend as the block it scrolls as. Only possible because
|
||||
* every row now has the same range: rows that disagreed about where the end was would disagree
|
||||
* about when to stretch.
|
||||
*
|
||||
* The gutter stays put while the text scrolls, so a line number is still there to read at the right
|
||||
* hand end of a long line. Its width is measured from the digit count of the line count in the very
|
||||
* style it is drawn in, so a nine-line file and a twelve-thousand-line file each get exactly what
|
||||
@@ -94,23 +106,30 @@ fun ScannedFile(content: String, language: Language?, modifier: Modifier = Modif
|
||||
fun FileViewer(lines: FileLines, modifier: Modifier = Modifier) {
|
||||
val style = codeStyle()
|
||||
val scroll = rememberScrollState()
|
||||
val overscroll = rememberOverscrollEffect()
|
||||
val gutter = gutterWidth(lines.size, style)
|
||||
val content = contentWidth(lines.columns, style)
|
||||
// One container around the whole file rather than one per line, so a selection can run across
|
||||
// lines -- the same arrangement the transcript uses.
|
||||
SelectionContainer(modifier) {
|
||||
LazyColumn(Modifier.fillMaxWidth()) {
|
||||
items(lines.size) { index ->
|
||||
Row(verticalAlignment = Alignment.Top) {
|
||||
LineNumber(index + 1, gutter, style)
|
||||
Text(
|
||||
lines.line(index),
|
||||
style = style,
|
||||
softWrap = false,
|
||||
// The scroll outside the width: the scrolling node's viewport is what
|
||||
// the row has room for, and its content is the whole file's widest line.
|
||||
modifier = Modifier.horizontalScroll(scroll).width(content),
|
||||
)
|
||||
// The stretch is drawn here, once, over everything the viewport holds; the rows below only
|
||||
// feed it. `clipToBounds` because a stretch draws outside the box it came from.
|
||||
Box(Modifier.fillMaxSize().clipToBounds().overscroll(overscroll)) {
|
||||
LazyColumn(Modifier.fillMaxSize()) {
|
||||
items(lines.size) { index ->
|
||||
Row(verticalAlignment = Alignment.Top) {
|
||||
LineNumber(index + 1, gutter, style)
|
||||
Text(
|
||||
lines.line(index),
|
||||
style = style,
|
||||
softWrap = false,
|
||||
// The scroll outside the width: the scrolling node's viewport is what
|
||||
// the row has room for, and its content is the whole file's widest
|
||||
// line. The shared effect is given to every row and rendered by none
|
||||
// of them -- see the box above.
|
||||
modifier = Modifier.horizontalScroll(scroll, overscroll).width(content),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user