android: detekt caught a callback that never reached the cards
Not a style finding. `onToggleItem` was added to BoardScreen's signature and read
inside NoteBoard — which is a separate top-level composable, not a nested one, so
the two were never connected. detekt reported it as an unused parameter; the
compiler would have called it an unresolved reference. Neither had run: Kotlin is
compiled at the "Unit tests" step, which is gated behind detekt, so nothing in this
lane had type-checked the Android changes yet.
Threaded properly now, which is what makes ticking a box from the board actually
work rather than merely appear to.
Two more from reading it again with that in mind:
* `when { item != null -> … onToggleItem(index, …) }` would not have compiled.
Kotlin does not infer that a non-null item implies a non-null index, so the
index stayed `Int?` against an `Int` parameter. Both are in the condition now.
* continueChecklist had six returns against detekt's limit of two. Collapsed to
one `when`, with the two intermediate values guarded on `typedNewline` —
`caret - 1` is only a real index once it is known to be the newline just typed.
This commit is contained in:
@@ -141,7 +141,12 @@ fun BoardScreen(
|
|||||||
when {
|
when {
|
||||||
state.loading -> LoadingBoard()
|
state.loading -> LoadingBoard()
|
||||||
state.notes.isEmpty() -> EmptyBoard(state)
|
state.notes.isEmpty() -> EmptyBoard(state)
|
||||||
else -> NoteBoard(notes = state.notes, onOpenNote = onOpenNote)
|
else ->
|
||||||
|
NoteBoard(
|
||||||
|
notes = state.notes,
|
||||||
|
onOpenNote = onOpenNote,
|
||||||
|
onToggleItem = onToggleItem,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
// `PullToRefreshBox` would be less code, but it takes no
|
// `PullToRefreshBox` would be less code, but it takes no
|
||||||
// `enabled`, so the modifier and the indicator are wired by
|
// `enabled`, so the modifier and the indicator are wired by
|
||||||
@@ -324,6 +329,7 @@ private fun DrawerRow(
|
|||||||
private fun NoteBoard(
|
private fun NoteBoard(
|
||||||
notes: List<Note>,
|
notes: List<Note>,
|
||||||
onOpenNote: (Note) -> Unit,
|
onOpenNote: (Note) -> Unit,
|
||||||
|
onToggleItem: (Note, Int, Boolean) -> Unit,
|
||||||
) {
|
) {
|
||||||
LazyVerticalStaggeredGrid(
|
LazyVerticalStaggeredGrid(
|
||||||
columns = StaggeredGridCells.Fixed(BOARD_COLUMNS),
|
columns = StaggeredGridCells.Fixed(BOARD_COLUMNS),
|
||||||
|
|||||||
@@ -109,7 +109,11 @@ private fun NoteBody(
|
|||||||
val index = itemAtLine[n]
|
val index = itemAtLine[n]
|
||||||
val item = index?.let { note.items.getOrNull(it) }
|
val item = index?.let { note.items.getOrNull(it) }
|
||||||
when {
|
when {
|
||||||
item != null -> ChecklistRow(item) { onToggleItem(index, !item.checked) }
|
// Both in the condition, not just `item`: Kotlin will not infer that a
|
||||||
|
// non-null item implies a non-null index, and `onToggleItem` needs the
|
||||||
|
// index smart-cast to act on it.
|
||||||
|
index != null && item != null ->
|
||||||
|
ChecklistRow(item) { onToggleItem(index, !item.checked) }
|
||||||
// Kept as a gap rather than dropped: it is the paragraph break
|
// Kept as a gap rather than dropped: it is the paragraph break
|
||||||
// somebody typed, and the card reads as a wall without it.
|
// somebody typed, and the card reads as a wall without it.
|
||||||
line.isBlank() -> Spacer(Modifier.height(4.dp))
|
line.isBlank() -> Spacer(Modifier.height(4.dp))
|
||||||
|
|||||||
@@ -396,21 +396,31 @@ private fun continueChecklist(
|
|||||||
new: TextFieldValue,
|
new: TextFieldValue,
|
||||||
): TextFieldValue {
|
): TextFieldValue {
|
||||||
val caret = new.selection.start
|
val caret = new.selection.start
|
||||||
if (new.selection.length != 0) return new
|
val typedNewline =
|
||||||
if (new.text.length != old.text.length + 1) return new
|
new.selection.length == 0 &&
|
||||||
if (caret == 0 || new.text[caret - 1] != '\n') return new
|
new.text.length == old.text.length + 1 &&
|
||||||
|
caret > 0 &&
|
||||||
|
new.text[caret - 1] == '\n'
|
||||||
|
// Both guarded on `typedNewline`, because caret - 1 is only a real index once it
|
||||||
|
// is known to be the newline that was just typed.
|
||||||
|
val lineStart = if (typedNewline) new.text.take(caret - 1).lastIndexOf('\n') + 1 else 0
|
||||||
|
val marker =
|
||||||
|
if (typedNewline) checklistContinuation(new.text.substring(lineStart, caret - 1)) else null
|
||||||
|
|
||||||
val before = new.text.take(caret - 1)
|
return when {
|
||||||
val lineStart = before.lastIndexOf('\n') + 1
|
marker == null -> new
|
||||||
val marker = checklistContinuation(before.substring(lineStart)) ?: return new
|
|
||||||
|
|
||||||
if (marker.isEmpty()) {
|
|
||||||
// An empty item: take the marker line away rather than adding another.
|
// An empty item: take the marker line away rather than adding another.
|
||||||
val text = new.text.take(lineStart) + new.text.substring(caret)
|
marker.isEmpty() ->
|
||||||
return TextFieldValue(text, TextRange(lineStart))
|
TextFieldValue(
|
||||||
|
new.text.take(lineStart) + new.text.substring(caret),
|
||||||
|
TextRange(lineStart),
|
||||||
|
)
|
||||||
|
else ->
|
||||||
|
TextFieldValue(
|
||||||
|
new.text.take(caret) + marker + new.text.substring(caret),
|
||||||
|
TextRange(caret + marker.length),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
val text = new.text.take(caret) + marker + new.text.substring(caret)
|
|
||||||
return TextFieldValue(text, TextRange(caret + marker.length))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private const val CHECKLIST_MARKER = "- [ ] "
|
private const val CHECKLIST_MARKER = "- [ ] "
|
||||||
|
|||||||
Reference in New Issue
Block a user