diff --git a/android/.editorconfig b/android/.editorconfig new file mode 100644 index 0000000..e8a9eab --- /dev/null +++ b/android/.editorconfig @@ -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 diff --git a/android/app/src/main/java/com/fabledsword/thoughtsync/ui/BoardScreen.kt b/android/app/src/main/java/com/fabledsword/thoughtsync/ui/BoardScreen.kt index 6bf27cf..c34d334 100644 --- a/android/app/src/main/java/com/fabledsword/thoughtsync/ui/BoardScreen.kt +++ b/android/app/src/main/java/com/fabledsword/thoughtsync/ui/BoardScreen.kt @@ -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) { 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 diff --git a/android/app/src/main/java/com/fabledsword/thoughtsync/ui/BoardViewModel.kt b/android/app/src/main/java/com/fabledsword/thoughtsync/ui/BoardViewModel.kt index c1803fe..81a862e 100644 --- a/android/app/src/main/java/com/fabledsword/thoughtsync/ui/BoardViewModel.kt +++ b/android/app/src/main/java/com/fabledsword/thoughtsync/ui/BoardViewModel.kt @@ -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 diff --git a/android/config/detekt.yml b/android/config/detekt.yml index 6bdffdb..d2a993c 100644 --- a/android/config/detekt.yml +++ b/android/config/detekt.yml @@ -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"