Two things at once, because they answer one question: what should this look like,
and what should it look like ON A PHONE.
IDENTITY IS SHARED, INTERACTION IS NOT. The card now renders exactly what the web
and desktop render — note colour, checklists, label chips, reminders — using the
same palette values, so a note looks like your note on every surface. The chrome
does not: the desktop's title bar and sidebar are wrong for a thumb.
* NoteTint.kt carries the Tailwind colours from frontend/src/notes/colors.ts
VALUE FOR VALUE, generated from tailwindcss 3.4 rather than eyeballed. Dark
tints keep the web's alpha (dark:bg-*-950/40) instead of a precomputed blend,
because Compose composites translucency over the background exactly as CSS
does.
* Dynamic colour is GONE. It was the more Android-native choice and it made the
app look like a different product — on a stock emulator with no wallpaper it
renders as undifferentiated grey, which is what the operator saw. Three peer
surfaces share one identity; the brand #F5C518 is the same value the web
manifest and the launcher icon already use.
* The board is a two-column staggered grid, the Compose equivalent of the CSS
multi-column NoteGrid.vue uses.
PHONE ERGONOMICS, chosen with the operator:
* Search IS the top bar. After writing a note, finding one is the most common
thing you do, and burying it behind an icon costs a tap every time. Debounced
180ms and cancelled per keystroke — without that a fast typist queues one
full-text query per character and results land out of order.
* A + button is the only way in. One obvious target beat a capture bar and a
button competing for the same job.
* Navigation moved into a drawer behind the search bar's menu icon, which is
where archive/trash/labels/reminders now live. They had nowhere to go once
search took the top bar, and would otherwise have been unreachable.
* The compose sheet asks note-or-list up front. On a phone those are different
typing tasks and switching halfway is worse than choosing at the start. A
list takes one item per line — fast to type, versus a tap per row.
Three new bindings the UI needed: search_notes, reminder_notes, list_labels.
Search goes through the CORE so "what matches" cannot drift between surfaces;
filtering the loaded list in Kotlin would have been less code and a different
product. reminder_notes is its own call because the core models it that way —
"has a reminder" cuts across archived and active alike.
Empty states are per-destination. "Nothing here yet" is encouraging on an empty
board, wrong in Trash, and misleading after a search where the notes exist but
did not match.
Verified locally before pushing: bindings generated from a host .so and read back,
ktlint and detekt clean from the image's pinned CLIs, cargo fmt/clippy/test green
(107 tests). Two detekt findings were fixed by extraction rather than by relaxing
the rules — this is the first Compose code in the repo and the thresholds should
have to earn their exceptions.
Still unbuilt: tapping a card does nothing. The editor is next.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
51 lines
2.8 KiB
TOML
51 lines
2.8 KiB
TOML
[versions]
|
|
# Pinned as a MATRIX, matching Minstrel's proven combination on the same JDK:
|
|
# - Gradle 9.1.0 supports JDK 25 (see gradle-wrapper.properties)
|
|
# - AGP 9.0.1 requires Gradle 9.1.0+
|
|
# - Kotlin 2.3.x is AGP 9's built-in Kotlin path
|
|
# ci-rust-android ships JDK 25, so the wrapper floor is load-bearing: an older
|
|
# Gradle fails on that JDK with an opaque "25.0.3" message.
|
|
agp = "9.0.1"
|
|
kotlin = "2.3.21"
|
|
compose-bom = "2026.05.01"
|
|
lifecycle = "2.8.7"
|
|
activity-compose = "1.9.3"
|
|
coroutines = "1.9.0"
|
|
|
|
# ktlint and detekt are NOT Gradle plugins here. ci-rust-android already ships
|
|
# both as pinned CLIs (M12 step 3), and the CI lane invokes those directly. Adding
|
|
# the Gradle plugins would mean a SECOND pinned version of each tool, resolved at
|
|
# build time, that has to be kept in lockstep with the image's by hand — and the
|
|
# first attempt at it failed outright, because the detekt version Minstrel pins
|
|
# (2.0.0-alpha.3) is not published to Maven Central or the plugin portal at all.
|
|
|
|
# JNA is not optional: uniffi's Kotlin bindings call into the .so through it.
|
|
# The @aar classifier matters — the plain jar has no Android native payload and
|
|
# fails at runtime with UnsatisfiedLinkError rather than at build time.
|
|
jna = "5.14.0"
|
|
|
|
junit = "4.13.2"
|
|
|
|
[libraries]
|
|
androidx-core-ktx = { module = "androidx.core:core-ktx", version = "1.13.1" }
|
|
androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "activity-compose" }
|
|
androidx-lifecycle-viewmodel-compose = { module = "androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "lifecycle" }
|
|
androidx-lifecycle-runtime-compose = { module = "androidx.lifecycle:lifecycle-runtime-compose", version.ref = "lifecycle" }
|
|
compose-bom = { module = "androidx.compose:compose-bom", version.ref = "compose-bom" }
|
|
compose-ui = { module = "androidx.compose.ui:ui" }
|
|
compose-ui-graphics = { module = "androidx.compose.ui:ui-graphics" }
|
|
compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling" }
|
|
compose-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview" }
|
|
compose-material3 = { module = "androidx.compose.material3:material3" }
|
|
# Icons only from -core, deliberately: it carries the common set (Menu, Search,
|
|
# Close, Add) and is already on the material3 path. -extended adds ~1,000 vectors
|
|
# for the handful the drawer would use.
|
|
compose-material-icons-core = { module = "androidx.compose.material:material-icons-core" }
|
|
kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "coroutines" }
|
|
jna = { module = "net.java.dev.jna:jna", version.ref = "jna" }
|
|
junit = { module = "junit:junit", version.ref = "junit" }
|
|
|
|
[plugins]
|
|
android-application = { id = "com.android.application", version.ref = "agp" }
|
|
compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
|