build: adopt Gradle version catalog (libs.versions.toml)

Centralize all plugin + dependency versions in gradle/libs.versions.toml (the
modern Gradle standard) and switch the root + app build scripts to the generated
libs.* / alias(libs.plugins.*) accessors. No version changes — a 1:1 migration of
the 57 hardcoded coordinates. Full assembleDebug + unit suite green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
null 2026-07-06 22:05:10 -05:00
parent fcc0d699fb
commit c71817241c
3 changed files with 204 additions and 78 deletions

View File

@ -1,13 +1,13 @@
import java.util.Properties import java.util.Properties
plugins { plugins {
id("com.android.application") alias(libs.plugins.android.application)
id("org.jetbrains.kotlin.android") alias(libs.plugins.kotlin.android)
id("org.jetbrains.kotlin.plugin.compose") alias(libs.plugins.kotlin.compose)
id("com.google.gms.google-services") alias(libs.plugins.google.services)
id("com.google.firebase.crashlytics") alias(libs.plugins.firebase.crashlytics)
id("com.google.dagger.hilt.android") alias(libs.plugins.hilt.android)
id("com.google.devtools.ksp") alias(libs.plugins.ksp)
} }
// Secrets resolve from local.properties (gitignored) first, then -P/gradle.properties, then env. // Secrets resolve from local.properties (gitignored) first, then -P/gradle.properties, then env.
@ -149,114 +149,111 @@ ksp {
} }
dependencies { dependencies {
val composeBom = platform("androidx.compose:compose-bom:2025.01.01") val composeBom = platform(libs.androidx.compose.bom)
implementation(composeBom) implementation(composeBom)
implementation("androidx.core:core-ktx:1.15.0") implementation(libs.androidx.core.ktx)
implementation("androidx.core:core-splashscreen:1.0.1") implementation(libs.androidx.core.splashscreen)
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.7") implementation(libs.androidx.lifecycle.runtime.ktx)
implementation("androidx.activity:activity-compose:1.9.3") implementation(libs.androidx.activity.compose)
// Compose // Compose
implementation("androidx.compose.ui:ui") implementation(libs.androidx.compose.ui)
implementation("androidx.compose.ui:ui-graphics") implementation(libs.androidx.compose.ui.graphics)
implementation("androidx.compose.ui:ui-tooling-preview") implementation(libs.androidx.compose.ui.tooling.preview)
implementation("androidx.compose.material3:material3") implementation(libs.androidx.compose.material3)
implementation("androidx.compose.material:material-icons-extended") implementation(libs.androidx.compose.material.icons.extended)
// Navigation // Navigation
implementation("androidx.navigation:navigation-compose:2.8.5") implementation(libs.androidx.navigation.compose)
// ViewModel // ViewModel + lifecycle-aware Compose state collection (collectAsStateWithLifecycle)
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.7") implementation(libs.androidx.lifecycle.viewmodel.compose)
// Lifecycle-aware Compose state collection (collectAsStateWithLifecycle) implementation(libs.androidx.lifecycle.runtime.compose)
implementation("androidx.lifecycle:lifecycle-runtime-compose:2.8.7")
// Firebase // Firebase
implementation(platform("com.google.firebase:firebase-bom:33.8.0")) implementation(platform(libs.firebase.bom))
implementation("com.google.firebase:firebase-auth-ktx") implementation(libs.firebase.auth.ktx)
implementation("com.google.firebase:firebase-firestore-ktx") implementation(libs.firebase.firestore.ktx)
implementation("com.google.firebase:firebase-messaging-ktx") implementation(libs.firebase.messaging.ktx)
implementation("com.google.firebase:firebase-config-ktx") implementation(libs.firebase.config.ktx)
implementation("com.google.firebase:firebase-analytics-ktx") implementation(libs.firebase.analytics.ktx)
implementation("com.google.firebase:firebase-crashlytics-ktx") implementation(libs.firebase.crashlytics.ktx)
implementation("com.google.firebase:firebase-appcheck-ktx") implementation(libs.firebase.appcheck.ktx)
implementation("com.google.firebase:firebase-appcheck-playintegrity") implementation(libs.firebase.appcheck.playintegrity)
debugImplementation("com.google.firebase:firebase-appcheck-debug") debugImplementation(libs.firebase.appcheck.debug)
// Hilt // Hilt
implementation("com.google.dagger:hilt-android:2.53.1") implementation(libs.hilt.android)
ksp("com.google.dagger:hilt-android-compiler:2.53.1") ksp(libs.hilt.android.compiler)
implementation("androidx.hilt:hilt-navigation-compose:1.2.0") implementation(libs.androidx.hilt.navigation.compose)
// Room // Room
implementation("androidx.room:room-runtime:2.6.1") implementation(libs.androidx.room.runtime)
implementation("androidx.room:room-ktx:2.6.1") implementation(libs.androidx.room.ktx)
ksp("androidx.room:room-compiler:2.6.1") ksp(libs.androidx.room.compiler)
// DataStore // DataStore
implementation("androidx.datastore:datastore-preferences:1.1.2") implementation(libs.androidx.datastore.preferences)
// Glance — home-screen "Today" widget (content-free: daily-question state + streak only) // Glance — home-screen "Today" widget (content-free: daily-question state + streak only)
implementation("androidx.glance:glance-appwidget:1.1.1") implementation(libs.androidx.glance.appwidget)
implementation("androidx.glance:glance-material3:1.1.1") implementation(libs.androidx.glance.material3)
// Encrypted storage // Encrypted storage
implementation("androidx.security:security-crypto:1.0.0") implementation(libs.androidx.security.crypto)
// Play Integrity API — runtime device integrity check // Play Integrity API — runtime device integrity check
implementation("com.google.android.play:integrity:1.4.0") implementation(libs.google.play.integrity)
// Firebase Functions — callable for server-side integrity token verification // Firebase Storage + Functions (callable for server-side integrity token verification)
implementation("com.google.firebase:firebase-storage-ktx") implementation(libs.firebase.storage.ktx)
implementation("com.google.firebase:firebase-functions-ktx") implementation(libs.firebase.functions.ktx)
// RevenueCat native Android SDK (group: com.revenuecat.purchases, artifact: purchases) // RevenueCat native Android SDK
implementation("com.revenuecat.purchases:purchases:8.20.0") implementation(libs.revenuecat.purchases)
// Image loading // Image loading (+ animated GIF/WebP for stickers/Bitmoji)
implementation("io.coil-kt:coil-compose:2.7.0") implementation(libs.coil.compose)
// Animated GIF / WebP support (for GIFs, stickers, Bitmoji from the keyboard) implementation(libs.coil.gif)
implementation("io.coil-kt:coil-gif:2.7.0")
// AppCompat — required by BiometricPrompt (needs FragmentActivity base) // AppCompat (BiometricPrompt needs FragmentActivity) + biometric app-lock
implementation("androidx.appcompat:appcompat:1.7.0") implementation(libs.androidx.appcompat)
// Biometric auth — recovery phrase reveal + app-level login lock implementation(libs.androidx.biometric)
implementation("androidx.biometric:biometric:1.1.0")
// Google Sign-In via Credential Manager // Google Sign-In via Credential Manager
implementation("androidx.credentials:credentials:1.3.0") implementation(libs.androidx.credentials)
implementation("androidx.credentials:credentials-play-services-auth:1.3.0") implementation(libs.androidx.credentials.play.services.auth)
implementation("com.google.android.libraries.identity.googleid:googleid:1.1.1") implementation(libs.google.identity.googleid)
// Coroutines // Coroutines
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0") implementation(libs.kotlinx.coroutines.android)
// E2EE: Google Tink (AEAD) + Bouncy Castle (Argon2id KDF) // E2EE: Google Tink (AEAD) + Bouncy Castle (Argon2id KDF)
implementation("com.google.crypto.tink:tink-android:1.13.0") implementation(libs.tink.android)
implementation("org.bouncycastle:bcprov-jdk18on:1.78.1") implementation(libs.bouncycastle.bcprov)
// Debug // Debug
debugImplementation("androidx.compose.ui:ui-tooling") debugImplementation(libs.androidx.compose.ui.tooling)
debugImplementation("androidx.compose.ui:ui-test-manifest") debugImplementation(libs.androidx.compose.ui.test.manifest)
// Unit tests — JVM only (no device/emulator required) // Unit tests — JVM only (no device/emulator required)
testImplementation("junit:junit:4.13.2") testImplementation(libs.junit)
// Reflection over the RetentionEvent sealed hierarchy (NoPlaintextInAnalyticsTest schema check) // Reflection over the RetentionEvent sealed hierarchy (NoPlaintextInAnalyticsTest schema check)
testImplementation(kotlin("reflect")) testImplementation(kotlin("reflect"))
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.9.0") testImplementation(libs.kotlinx.coroutines.test)
testImplementation("io.mockk:mockk:1.13.14") testImplementation(libs.mockk)
// Real org.json on the JVM test classpath so codec round-trips run (Android's stubbed JSONObject // Real org.json on the JVM test classpath so codec round-trips run (Android's stubbed JSONObject
// returns defaults under unitTests.isReturnDefaultValues). // returns defaults under unitTests.isReturnDefaultValues).
testImplementation("org.json:json:20240303") testImplementation(libs.org.json)
// Canonical-vector capture harness (paired-CI for iOS↔Android E2EE fixture fill) // Canonical-vector capture harness (paired-CI for iOS↔Android E2EE fixture fill)
androidTestImplementation("androidx.test.ext:junit:1.1.5") androidTestImplementation(libs.androidx.test.ext.junit)
androidTestImplementation("androidx.test:runner:1.5.2") androidTestImplementation(libs.androidx.test.runner)
// Instrumented Compose render smoke (first-run screens) — the on-device net for the // Instrumented Compose render smoke (first-run screens) — the on-device net for the
// "composes fine, crashes on first paint" class (e.g. O-ONBOARD-001). Needs the BOM so the // "composes fine, crashes on first paint" class (e.g. O-ONBOARD-001). Needs the BOM so the
// ui-test version matches the app's Compose; ui-test-manifest (debug, above) hosts the ComposeRule. // ui-test version matches the app's Compose; ui-test-manifest (debug, above) hosts the ComposeRule.
androidTestImplementation(composeBom) androidTestImplementation(composeBom)
androidTestImplementation("androidx.compose.ui:ui-test-junit4") androidTestImplementation(libs.androidx.compose.ui.test.junit4)
} }

View File

@ -1,9 +1,9 @@
plugins { plugins {
id("com.android.application") version "8.7.3" apply false alias(libs.plugins.android.application) apply false
id("org.jetbrains.kotlin.android") version "2.0.21" apply false alias(libs.plugins.kotlin.android) apply false
id("org.jetbrains.kotlin.plugin.compose") version "2.0.21" apply false alias(libs.plugins.kotlin.compose) apply false
id("com.google.gms.google-services") version "4.4.2" apply false alias(libs.plugins.google.services) apply false
id("com.google.firebase.crashlytics") version "3.0.2" apply false alias(libs.plugins.firebase.crashlytics) apply false
id("com.google.dagger.hilt.android") version "2.53.1" apply false alias(libs.plugins.hilt.android) apply false
id("com.google.devtools.ksp") version "2.0.21-1.0.28" apply false alias(libs.plugins.ksp) apply false
} }

129
gradle/libs.versions.toml Normal file
View File

@ -0,0 +1,129 @@
[versions]
# Build plugins
agp = "8.7.3"
kotlin = "2.0.21"
ksp = "2.0.21-1.0.28"
googleServices = "4.4.2"
crashlyticsPlugin = "3.0.2"
hilt = "2.53.1"
# AndroidX / Compose
coreKtx = "1.15.0"
splashscreen = "1.0.1"
lifecycle = "2.8.7"
activityCompose = "1.9.3"
composeBom = "2025.01.01"
navigationCompose = "2.8.5"
hiltNavigationCompose = "1.2.0"
room = "2.6.1"
datastore = "1.1.2"
glance = "1.1.1"
securityCrypto = "1.0.0"
appcompat = "1.7.0"
biometric = "1.1.0"
credentials = "1.3.0"
# Firebase / Google
firebaseBom = "33.8.0"
playIntegrity = "1.4.0"
googleid = "1.1.1"
# Third-party
revenuecat = "8.20.0"
coil = "2.7.0"
coroutines = "1.9.0"
tink = "1.13.0"
bouncycastle = "1.78.1"
# Test
junit = "4.13.2"
mockk = "1.13.14"
orgJson = "20240303"
androidxTestJunit = "1.1.5"
androidxTestRunner = "1.5.2"
[libraries]
# AndroidX core
androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "coreKtx" }
androidx-core-splashscreen = { module = "androidx.core:core-splashscreen", version.ref = "splashscreen" }
androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "activityCompose" }
androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "appcompat" }
androidx-biometric = { module = "androidx.biometric:biometric", version.ref = "biometric" }
# Lifecycle
androidx-lifecycle-runtime-ktx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "lifecycle" }
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 (versions from the BOM)
androidx-compose-bom = { module = "androidx.compose:compose-bom", version.ref = "composeBom" }
androidx-compose-ui = { module = "androidx.compose.ui:ui" }
androidx-compose-ui-graphics = { module = "androidx.compose.ui:ui-graphics" }
androidx-compose-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview" }
androidx-compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling" }
androidx-compose-ui-test-manifest = { module = "androidx.compose.ui:ui-test-manifest" }
androidx-compose-ui-test-junit4 = { module = "androidx.compose.ui:ui-test-junit4" }
androidx-compose-material3 = { module = "androidx.compose.material3:material3" }
androidx-compose-material-icons-extended = { module = "androidx.compose.material:material-icons-extended" }
# Navigation / Hilt
androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "navigationCompose" }
hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hilt" }
hilt-android-compiler = { module = "com.google.dagger:hilt-android-compiler", version.ref = "hilt" }
androidx-hilt-navigation-compose = { module = "androidx.hilt:hilt-navigation-compose", version.ref = "hiltNavigationCompose" }
# Room
androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "room" }
androidx-room-ktx = { module = "androidx.room:room-ktx", version.ref = "room" }
androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "room" }
# DataStore / Glance / Security
androidx-datastore-preferences = { module = "androidx.datastore:datastore-preferences", version.ref = "datastore" }
androidx-glance-appwidget = { module = "androidx.glance:glance-appwidget", version.ref = "glance" }
androidx-glance-material3 = { module = "androidx.glance:glance-material3", version.ref = "glance" }
androidx-security-crypto = { module = "androidx.security:security-crypto", version.ref = "securityCrypto" }
# Credentials (Google Sign-In)
androidx-credentials = { module = "androidx.credentials:credentials", version.ref = "credentials" }
androidx-credentials-play-services-auth = { module = "androidx.credentials:credentials-play-services-auth", version.ref = "credentials" }
google-identity-googleid = { module = "com.google.android.libraries.identity.googleid:googleid", version.ref = "googleid" }
# Firebase (versions from the BOM)
firebase-bom = { module = "com.google.firebase:firebase-bom", version.ref = "firebaseBom" }
firebase-auth-ktx = { module = "com.google.firebase:firebase-auth-ktx" }
firebase-firestore-ktx = { module = "com.google.firebase:firebase-firestore-ktx" }
firebase-messaging-ktx = { module = "com.google.firebase:firebase-messaging-ktx" }
firebase-config-ktx = { module = "com.google.firebase:firebase-config-ktx" }
firebase-analytics-ktx = { module = "com.google.firebase:firebase-analytics-ktx" }
firebase-crashlytics-ktx = { module = "com.google.firebase:firebase-crashlytics-ktx" }
firebase-appcheck-ktx = { module = "com.google.firebase:firebase-appcheck-ktx" }
firebase-appcheck-playintegrity = { module = "com.google.firebase:firebase-appcheck-playintegrity" }
firebase-appcheck-debug = { module = "com.google.firebase:firebase-appcheck-debug" }
firebase-storage-ktx = { module = "com.google.firebase:firebase-storage-ktx" }
firebase-functions-ktx = { module = "com.google.firebase:firebase-functions-ktx" }
google-play-integrity = { module = "com.google.android.play:integrity", version.ref = "playIntegrity" }
# Third-party
revenuecat-purchases = { module = "com.revenuecat.purchases:purchases", version.ref = "revenuecat" }
coil-compose = { module = "io.coil-kt:coil-compose", version.ref = "coil" }
coil-gif = { module = "io.coil-kt:coil-gif", version.ref = "coil" }
kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "coroutines" }
tink-android = { module = "com.google.crypto.tink:tink-android", version.ref = "tink" }
bouncycastle-bcprov = { module = "org.bouncycastle:bcprov-jdk18on", version.ref = "bouncycastle" }
# Test
junit = { module = "junit:junit", version.ref = "junit" }
kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "coroutines" }
mockk = { module = "io.mockk:mockk", version.ref = "mockk" }
org-json = { module = "org.json:json", version.ref = "orgJson" }
androidx-test-ext-junit = { module = "androidx.test.ext:junit", version.ref = "androidxTestJunit" }
androidx-test-runner = { module = "androidx.test:runner", version.ref = "androidxTestRunner" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
google-services = { id = "com.google.gms.google-services", version.ref = "googleServices" }
firebase-crashlytics = { id = "com.google.firebase.crashlytics", version.ref = "crashlyticsPlugin" }
hilt-android = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }