Skip to content

Update Quickstart for Android Kotlin to v5#239

Open
Aaron LaBeau (biozal) wants to merge 9 commits intomainfrom
da-138-update-v5-kotlin-android
Open

Update Quickstart for Android Kotlin to v5#239
Aaron LaBeau (biozal) wants to merge 9 commits intomainfrom
da-138-update-v5-kotlin-android

Conversation

@biozal
Copy link
Copy Markdown
Contributor

@biozal Aaron LaBeau (biozal) commented Jan 31, 2026

Summary

  • Ditto SDK 4.14.3 → 5.0.0 (artifact rename: live.ditto:dittocom.ditto:ditto-kotlin)
  • Kotlin 2.1.0 → 2.3.20 + migration off the deprecated kotlinOptions DSL
  • JVM target 11 → 17 to match the SDK's bytecode level
  • Compose BOM, AndroidX, Koin, navigation-compose, lifecycle, datastore, monitor all bumped
  • Two-phase code-quality pass covering correctness, theming, accessibility, ViewModel architecture, and tests
  • 5 new unit tests for Task.fromJson covering malformed JSON, missing fields, type-mismatch coercion, round-trip, and unique IDs
  • README updated to reflect the v5 rename ("App ID" → "Database ID") and v5.0.0 API reference

Why

The quickstart was failing to build with a Kotlin compiler crash (source must not be null inside FirIncompatibleClassExpressionChecker). Root cause: Koin 4.2.1 transitively
pulls kotlin-stdlib:2.3.20, whose metadata is unreadable by the Kotlin 2.1.0 compiler. Beyond fixing the build, the existing code had a number of accumulated Android/Compose anti-patterns that this PR cleans up.


Build / dependency changes

Component Before After Reason
Ditto SDK live.ditto:ditto:4.14.3 com.ditto:ditto-kotlin:5.0.0 v5 GA, new artifact coordinates
Kotlin 2.1.0 2.3.20 Required to read transitive 2.3.0 metadata; also drops a known 2.1.0 compiler crash
AGP 8.9.3 8.9.3 unchanged
Compose BOM 2025.07.00 2026.04.01 latest stable
activityCompose 1.10.1 1.13.0 latest
navigationCompose 2.9.2 2.9.8 latest
lifecycle-runtime-ktx 2.9.2 2.10.0 latest
lifecycle-runtime-compose absent 2.10.0 needed for collectAsStateWithLifecycle
material-icons-extended absent (BOM) needed for Icons.Outlined.Edit
datastore-preferences 1.1.7 1.2.1 latest
koin-bom 4.1.0 4.2.1 latest
coreKtx 1.16.0 1.18.0 latest
junitVersion (androidx) 1.2.1 1.3.0 latest
espressoCore 3.6.1 3.7.0 latest
runtimeLivedata 1.8.3 1.11.0 latest
monitor 1.7.2 1.8.0 latest
org.json:json absent 20240303 (testImpl) host-JVM JSONObject for unit tests
JVM target 11 17 match SDK's JDK 17 bytecode
Kotlin DSL kotlinOptions { jvmTarget = "11" } kotlin { compilerOptions { jvmTarget.set(JvmTarget.JVM_17) } } kotlinOptions removed in Kotlin 2.3
testOptions.unitTests.isReturnDefaultValues absent true lets host tests call android.util.Log
.gitignore + .kotlin/ Kotlin 2.x daemon cache directory

Code-quality changes

Correctness / safety

Area File Before After
Permission request MainActivity.kt Deprecated Activity.requestPermissions(...) with the result silently dropped
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()), denied perms logged
Side effect in composition EditScreen.kt editScreenViewModel.setupWithTask(taskId) ran on every recomposition Wrapped in LaunchedEffect(taskId)
ViewModel init order TasksListScreenViewModel.kt, EditScreenViewModel.kt Property initializer touched ditto (lateinit) before the init { check(...) } guard
Top-of-class init block runs the precondition first; properties initialize after
Sync state flash TasksListScreenViewModel.kt MutableStateFlow(true) flashed true on cold start before disk read syncEnabled derived directly from DataStore via
stateIn(..., SharingStarted.Eagerly); separate collector applies start/stop
Unchecked JSON casts Task.kt json["done"] as Boolean threw ClassCastException on type mismatch, bypassing JSONException catch optBoolean(...) / optString(...)
with safe defaults
Token in shipping UI TasksListScreen.kt DITTO_PLAYGROUND_TOKEN rendered into top bar in all builds Gated behind BuildConfig.DEBUG

Accessibility / theming

Area File Before After
Wrong content description TaskRow.kt Edit icon contentDescription = "Delete" (copy-paste bug) R.string.action_edit
Hardcoded brand color TasksListScreen.kt, EditScreen.kt colorResource(R.color.blue_700) / Color.White everywhere MaterialTheme.colorScheme.primary / onPrimary
/ primaryContainer / onPrimaryContainer
Hardcoded destructive color EditForm.kt Color.Red / Color.White for delete button MaterialTheme.colorScheme.error / onError
Color resource bug colors.xml blue_700 was the same hex as blue_500 (#3B82F6) Restored to actual Tailwind blue-700 (#1D4ED8)
Theme Theme.kt, Color.kt Default purple template + dynamicColor = true overridden by hardcoded blues Brand lightColorScheme/darkColorScheme driven by
Blue200/500/700/900; dynamicColor opt-in (default false) so brand wins
Hardcoded UI strings TasksListScreen.kt, EditScreen.kt, EditForm.kt, TaskRow.kt "Ditto Tasks", "New Task", "Save", "Delete", "Cancel", "Confirm Deletion", "Title:",
"Is Complete:", etc. inline All extracted to strings.xml (15 new keys)

Compose / architecture

Area File Change
List identity TasksListScreen.kt LazyColumn items(tasks, key = { it._id }) for stable identity / correct animations
Star imports EditForm.kt Replaced androidx.compose.foundation.layout.* / androidx.compose.material3.* with explicit imports; named horizontalArrangement
Typography TasksListScreen.kt Replaced raw TextStyle(fontSize = 10.sp) with MaterialTheme.typography.labelSmall

Tests

Area File Change
Placeholder unit test removed ExampleUnitTest.kt Deleted (addition_isCorrect() placeholder)
Real Task test coverage data/TaskTest.kt (new) 5 tests: round-trip via toMap, malformed-JSON fallback, missing-fields defaults, type-mismatch coercion (the case the
old as Boolean cast crashed on), default-id uniqueness
Silent-pass branch removed TasksUITest.kt Test no longer catches IllegalStateException("no compose hierarchies") and turns it into assertTrue(... .isNotEmpty()) — a
UI test with no UI now fails loudly. Refactored: extracted resolveTestDocumentTitle(), runCatching instead of nested try, named constants for timeout and arg key.

Verification

Check Result
./gradlew --stop && ./gradlew clean assembleDebug ✅ BUILD SUCCESSFUL
./gradlew testDebugUnitTest ✅ 5/5 tests passing in TaskTest
TasksUITest (instrumented) ⚠️ Requires connected device/emulator; run on BrowserStack/CI as before

Test plan

  • Build cleanly on a fresh checkout: ./gradlew --stop && ./gradlew clean assembleDebug
  • Install on a device/emulator: ./gradlew installDebug
  • Verify the task list renders, the four seed tasks appear, and the Sync switch reflects the persisted value (no flash to true on cold start)
  • Toggle a task done/undone and confirm the list updates immediately
  • Tap + → enter a title → Save; confirm the task appears in the list
  • Tap a task's edit (pencil) icon → modify → Save; confirm the change persists
  • Tap a task's delete (trash) icon → confirm dialog appears; Delete removes it (soft-delete)
  • Confirm a second device/peer syncs the same documents
  • On Android 12+, confirm dynamic color is not applied by default (brand blue wins)
  • Run TalkBack — verify the edit and delete icons announce correctly (the previous "Delete"/"Delete" duplicate is fixed)

@biozal Aaron LaBeau (biozal) marked this pull request as ready for review May 5, 2026 21:01
Copilot AI review requested due to automatic review settings May 5, 2026 21:01
@biozal Aaron LaBeau (biozal) changed the title Draft: Update Quickstart for Android Kotlin to v5 - DO NOT MERGE Update Quickstart for Android Kotlin to v5 May 5, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the Android Kotlin quickstart app to use Ditto Kotlin SDK v5, modernizing the app’s Ditto initialization/auth flow and moving UI/viewmodels toward Flow/StateFlow and lifecycle-aware Compose collection.

Changes:

  • Upgrades Ditto dependency to v5 (com.ditto:ditto-kotlin:5.0.0) and updates related AndroidX/Kotlin tooling versions.
  • Refactors app state to use StateFlow + collectAsStateWithLifecycle, updates theming/resources, and improves runtime permission handling.
  • Adds focused unit tests for the Task model JSON parsing and tightens the UI test behavior.

Reviewed changes

Copilot reviewed 21 out of 21 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
android-kotlin/README.md Updates docs links and setup wording; adds Android CLI/Skills note.
android-kotlin/QuickStartTasks/gradle/libs.versions.toml Bumps tool/library versions; switches Ditto artifact coordinates; adds JSON + compose-related libs.
android-kotlin/QuickStartTasks/app/src/test/java/live/ditto/quickstart/tasks/ExampleUnitTest.kt Removes placeholder unit test.
android-kotlin/QuickStartTasks/app/src/test/java/live/ditto/quickstart/tasks/data/TaskTest.kt Adds unit tests validating Task.fromJson behavior and defaults.
android-kotlin/QuickStartTasks/app/src/main/res/values/strings.xml Centralizes UI strings and content descriptions for Compose screens.
android-kotlin/QuickStartTasks/app/src/main/res/values/colors.xml Adjusts brand color values/formatting.
android-kotlin/QuickStartTasks/app/src/main/java/live/ditto/quickstart/tasks/ui/theme/Theme.kt Updates Material3 color schemes and disables dynamic color by default.
android-kotlin/QuickStartTasks/app/src/main/java/live/ditto/quickstart/tasks/ui/theme/Color.kt Adds brand color constants matching resource colors.
android-kotlin/QuickStartTasks/app/src/main/java/live/ditto/quickstart/tasks/TasksApplication.kt Replaces v4 initialization with v5 Ditto config and authentication setup.
android-kotlin/QuickStartTasks/app/src/main/java/live/ditto/quickstart/tasks/MainActivity.kt Updates permission request flow and enables edge-to-edge.
android-kotlin/QuickStartTasks/app/src/main/java/live/ditto/quickstart/tasks/list/TasksListScreenViewModel.kt Moves tasks + sync state to StateFlow; refactors sync start/stop and store observation.
android-kotlin/QuickStartTasks/app/src/main/java/live/ditto/quickstart/tasks/list/TasksListScreen.kt Switches from LiveData to lifecycle-aware Flow collection; string/resource cleanup; stable list keys.
android-kotlin/QuickStartTasks/app/src/main/java/live/ditto/quickstart/tasks/list/TaskRow.kt Improves accessibility strings for icons/content descriptions.
android-kotlin/QuickStartTasks/app/src/main/java/live/ditto/quickstart/tasks/edit/EditScreenViewModel.kt Migrates edit state to StateFlow and updates Ditto queries accordingly.
android-kotlin/QuickStartTasks/app/src/main/java/live/ditto/quickstart/tasks/edit/EditScreen.kt Moves setup side-effect into LaunchedEffect; switches to lifecycle-aware Flow collection.
android-kotlin/QuickStartTasks/app/src/main/java/live/ditto/quickstart/tasks/edit/EditForm.kt Replaces hardcoded strings/colors with resources and Material theme colors.
android-kotlin/QuickStartTasks/app/src/main/java/live/ditto/quickstart/tasks/DittoHandler.kt Introduces explicit Ditto singleton initialization for v5.
android-kotlin/QuickStartTasks/app/src/main/java/live/ditto/quickstart/tasks/data/Task.kt Adds toMap() and makes JSON parsing more defensive via opt* APIs.
android-kotlin/QuickStartTasks/app/src/androidTest/java/live/ditto/quickstart/tasks/TasksUITest.kt Refactors UI test to fail loudly without a Compose hierarchy and clarifies title resolution.
android-kotlin/QuickStartTasks/app/build.gradle.kts Updates SDK levels/JVM target; adds lifecycle-runtime-compose + JSON test dep; adjusts env parsing.
android-kotlin/QuickStartTasks/.gitignore Ignores .kotlin/ directory.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread android-kotlin/README.md Outdated
Comment thread android-kotlin/QuickStartTasks/app/build.gradle.kts
Comment thread android-kotlin/QuickStartTasks/app/src/main/res/values/strings.xml Outdated
Comment thread android-kotlin/README.md
Aaron LaBeau (biozal) and others added 4 commits May 5, 2026 16:10
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants