The same pass the server had, on the Kotlin side: comments restating what the code says are gone, and the ones recording a measurement, a constraint or an incident are kept but cut to a few lines each. 6540 comment lines to 5674, and 920 lines off the app. Two doc comments had drifted onto the item above the one they describe -- `contextAfter`'s onto `sessionWorking` in Events.kt, and `UsageMonitor`'s equivalent on the server was fixed in the previous commit. Each is back on its own item, which is the only non-comment line this diff moves. The comments are reflowed to the column limit at their own indentation: several were written wide, and ktfmt re-wrapped them into lines holding a single orphan word. `/tmp` script, not kept -- ktfmt is idempotent over the result, which is the check. Left alone deliberately: this codebase's remaining comment density is high because the comments carry things the code cannot say -- what a null means, what a number was measured against, which bug a guard exists for. Of the 238 one-line doc comments in the app, five were pure restatement of the name and were removed; the rest each say something the signature does not. ktfmtFormat, compileDebugKotlin, lintDebug and testDebugUnitTest pass; cargo test (127), clippy --all-targets and fmt still clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
96 lines
4.1 KiB
Kotlin
96 lines
4.1 KiB
Kotlin
package com.example.aiapp
|
|
|
|
import androidx.compose.foundation.layout.Box
|
|
import androidx.compose.foundation.layout.Row
|
|
import androidx.compose.foundation.layout.Spacer
|
|
import androidx.compose.foundation.layout.height
|
|
import androidx.compose.foundation.layout.width
|
|
import androidx.compose.material3.CircularProgressIndicator
|
|
import androidx.compose.material3.MaterialTheme
|
|
import androidx.compose.material3.Text
|
|
import androidx.compose.runtime.Composable
|
|
import androidx.compose.ui.Alignment
|
|
import androidx.compose.ui.Modifier
|
|
import androidx.compose.ui.draw.drawWithContent
|
|
import androidx.compose.ui.geometry.Offset
|
|
import androidx.compose.ui.geometry.Rect
|
|
import androidx.compose.ui.graphics.ColorFilter
|
|
import androidx.compose.ui.graphics.ColorMatrix
|
|
import androidx.compose.ui.graphics.Paint
|
|
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
|
|
import androidx.compose.ui.graphics.graphicsLayer
|
|
import androidx.compose.ui.unit.dp
|
|
|
|
/**
|
|
* An item something is happening to: dimmed, drained of colour, inert, with a spinner and the name
|
|
* of the operation over it.
|
|
*
|
|
* One composable rather than a pattern each list repeats, because "this row is busy" has to look
|
|
* the same in the import list and the session list or the appearance becomes a per-screen dialect.
|
|
*
|
|
* [label] names the operation and `null` means none is running. One parameter rather than a boolean
|
|
* beside a string, which can disagree. It is a *word* because a spinner alone cannot say which
|
|
* operation this is -- deleting and importing are different in kind.
|
|
*
|
|
* It does **not** make the row inert; the caller disables its own click handling while it passes a
|
|
* label. That was the other way round at first -- an overlay consuming pointer events -- and it
|
|
* swallowed the drag along with the tap, so a list could not be scrolled while anything in it was
|
|
* busy.
|
|
*/
|
|
@Composable
|
|
fun BusyItem(label: String?, content: @Composable () -> Unit) {
|
|
Box {
|
|
Box(Modifier.busy(label != null)) { content() }
|
|
if (label != null) {
|
|
Box(Modifier.matchParentSize(), contentAlignment = Alignment.Center) {
|
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
|
CircularProgressIndicator(
|
|
modifier = Modifier.width(16.dp).height(16.dp),
|
|
strokeWidth = 2.dp,
|
|
color = MaterialTheme.colorScheme.onSurface,
|
|
)
|
|
Spacer(Modifier.width(8.dp))
|
|
// Full strength, over content that is not: the operation is the one thing on
|
|
// this row that is still current, and it has to read against a card whose own
|
|
// text is still visible behind it.
|
|
Text(
|
|
label,
|
|
style = MaterialTheme.typography.labelLarge,
|
|
color = MaterialTheme.colorScheme.onSurface,
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* How an item looks while it is being acted on: darker, and nearly grey.
|
|
*
|
|
* Both, rather than either alone. Dimming by itself is the same cue as a disabled control, so a
|
|
* busy row read as one more thing that could not be tapped. Draining the colour is what says the
|
|
* row is *suspended* -- the status word and everything else that means something by its colour stop
|
|
* meaning it for as long as the operation runs, which is exactly true.
|
|
*
|
|
* Not all the way to grey: a row with no colour left is hard to find again in a list.
|
|
*/
|
|
private fun Modifier.busy(busy: Boolean): Modifier =
|
|
if (!busy) this
|
|
else
|
|
this.graphicsLayer { alpha = 0.5f }
|
|
.drawWithContent {
|
|
drawIntoCanvas { canvas ->
|
|
canvas.saveLayer(
|
|
Rect(Offset.Zero, size),
|
|
Paint().apply {
|
|
colorFilter =
|
|
ColorFilter.colorMatrix(
|
|
ColorMatrix().apply { setToSaturation(0.2f) }
|
|
)
|
|
},
|
|
)
|
|
drawContent()
|
|
canvas.restore()
|
|
}
|
|
}
|