M12 — the Android client, end to end #2

Merged
bvandeusen merged 86 commits from dev into main 2026-08-21 08:53:58 -04:00
4 changed files with 49 additions and 8 deletions
Showing only changes of commit dee71dffb3 - Show all commits
+15
View File
@@ -0,0 +1,15 @@
root = true
[*.{kt,kts}]
# ktlint's standard function-naming rule doesn't know about Compose, where
# PascalCase @Composable functions are the universal convention — every
# mainstream Compose codebase would fail it. This is ktlint's own supported
# exemption, and it mirrors the equivalent detekt override in config/detekt.yml.
ktlint_function_naming_ignore_when_annotated_with = Composable
# 120 rather than ktlint's looser default: this is a phone UI with deeply nested
# Compose calls, and a hard-ish ceiling is what keeps the nesting from becoming
# unreadable rather than merely long.
max_line_length = 120
indent_size = 4
insert_final_newline = true
@@ -2,6 +2,7 @@ package com.fabledsword.thoughtsync.ui
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
@@ -106,7 +107,7 @@ private fun CaptureField(
private fun NoteList(notes: List<Note>) {
LazyColumn(
modifier = Modifier.fillMaxSize(),
contentPadding = androidx.compose.foundation.layout.PaddingValues(16.dp),
contentPadding = PaddingValues(16.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
// Keyed by id so Compose reuses rows across a refresh instead of
@@ -31,7 +31,9 @@ data class BoardState(
* (The sync methods are the exception: those are `suspend` on the Kotlin side
* already, because uniffi bridges the Rust async to coroutines.)
*/
class BoardViewModel(private val core: ThoughtSync) : ViewModel() {
class BoardViewModel(
private val core: ThoughtSync,
) : ViewModel() {
var state by mutableStateOf(BoardState())
private set
+29 -6
View File
@@ -1,19 +1,42 @@
# Per-rule overrides layered on top of detekt's defaults
# (`buildUponDefaultConfig = true` in the :app `detekt {}` block).
# (`--build-upon-default-config` on the CLI invocation in the Android lane).
#
# The pre-2.0 `build:` top-level was removed; failure-on-finding is controlled by
# the Gradle DSL's `failOnSeverity` option instead.
# The pre-2.0 `build:` top-level was removed; failure is controlled by the CLI's
# exit code instead.
naming:
# Composables conventionally use PascalCase function names. Matches every
# mainstream Compose codebase, and Minstrel's config for the same reason.
# mainstream Compose codebase, and mirrors the ktlint exemption in
# android/.editorconfig — the two tools have to agree or one of them is always
# wrong.
FunctionNaming:
ignoreAnnotated:
- "Composable"
style:
# The generated uniffi bindings are excluded at the Gradle level, but a
# magic-number complaint about a Compose dp value is noise rather than a smell.
MagicNumber:
ignoreAnnotated:
- "Composable"
# Colour literals and dp constants are declared as named properties, which is
# exactly the "define it as a well-named constant" the rule asks for — the
# number simply appears in the declaration itself. Flagging
# `private val Brand = Color(0xFFF5C518)` would demand a constant holding the
# constant.
ignorePropertyDeclaration: true
exceptions:
TooGenericExceptionCaught:
# Catching broadly is DELIBERATE in these two places, and each site says so.
#
# * the ViewModel — a note that fails to save must become a visible error
# banner, never a crash. Narrowing this would mean an unanticipated
# failure takes the app down instead of being reported, which is strictly
# worse for the user.
# * the Application — the store failing to open is the one thing that must
# still let the app start, so it can explain itself.
#
# Scoped to those paths rather than disabled globally: elsewhere the rule is
# right and still applies.
excludes:
- "**/ui/**"
- "**/ThoughtSyncApplication.kt"