Add a guided, F-Droid-safe onboarding step and an Advanced Settings recovery row that let users move LibreMail to "Unrestricted" battery usage, so IMAP IDLE push (IdleService) and periodic WorkManager sync aren't throttled or killed by Doze. Deep-links to the system app-details screen rather than the restricted REQUEST_IGNORE_BATTERY_OPTIMIZATIONS dialog, so it needs no new permission and is safe on Play (#17) and F-Droid (#16). - BatteryPromptDecision: pure, unit-tested gate (supported && !unrestricted && !handled) - BatteryOptimizationManager: reads isIgnoringBatteryOptimizations, builds the deep-link intent - Onboarding step shown after the first account is added; skipped when already unrestricted or already handled; re-checks status on resume - Advanced Settings row shows current status and re-opens the system screen - battery_prompt_handled flag persisted in the settings DataStore (kept out of AppSettings) - Unit tests for the decision + view model; Espresso E2E for the step Closes #49 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
99 lines
5.7 KiB
TOML
99 lines
5.7 KiB
TOML
[versions]
|
|
agp = "9.2.0"
|
|
kotlin = "2.4.0"
|
|
ksp = "2.3.9"
|
|
hilt = "2.60"
|
|
hiltNavigationCompose = "1.3.0"
|
|
coreKtx = "1.17.0"
|
|
lifecycle = "2.9.4"
|
|
activityCompose = "1.12.4"
|
|
navigationCompose = "2.9.8"
|
|
webkit = "1.12.1"
|
|
composeBom = "2026.06.00"
|
|
room = "2.8.4"
|
|
sqlcipher = "4.16.0"
|
|
datastore = "1.2.1"
|
|
work = "2.11.2"
|
|
coroutines = "1.10.2"
|
|
appauth = "0.11.1"
|
|
angusMail = "2.0.5"
|
|
junit = "4.13.2"
|
|
androidxJunit = "1.2.1"
|
|
espresso = "3.7.0"
|
|
turbine = "1.2.1"
|
|
mockk = "1.14.11"
|
|
greenmail = "2.1.9"
|
|
errorprone = "2.50.0"
|
|
# Lint/format. ktlint owns formatting; detekt owns static analysis (formatting ruleset off).
|
|
# detekt 2.0 is the only line with Gradle 9 support (stable 1.23.x tops out at Gradle 8.12).
|
|
ktlint = "14.2.0"
|
|
detekt = "2.0.0-alpha.5"
|
|
|
|
[libraries]
|
|
# AndroidX core / lifecycle / activity / navigation
|
|
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
|
androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycle" }
|
|
androidx-lifecycle-runtime-compose = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "lifecycle" }
|
|
androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "lifecycle" }
|
|
androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" }
|
|
androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigationCompose" }
|
|
androidx-webkit = { group = "androidx.webkit", name = "webkit", version.ref = "webkit" }
|
|
|
|
# Compose (versions managed by the BOM)
|
|
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }
|
|
androidx-compose-ui = { group = "androidx.compose.ui", name = "ui" }
|
|
androidx-compose-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
|
|
androidx-compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
|
|
androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
|
|
androidx-compose-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
|
|
androidx-compose-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
|
|
androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" }
|
|
androidx-compose-material-icons-core = { group = "androidx.compose.material", name = "material-icons-core" }
|
|
|
|
# Hilt (DI)
|
|
hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" }
|
|
# Pulled onto the compile classpath because Hilt/Dagger generated code references it.
|
|
error-prone-annotations = { group = "com.google.errorprone", name = "error_prone_annotations", version.ref = "errorprone" }
|
|
hilt-compiler = { group = "com.google.dagger", name = "hilt-compiler", version.ref = "hilt" }
|
|
androidx-hilt-navigation-compose = { group = "androidx.hilt", name = "hilt-navigation-compose", version.ref = "hiltNavigationCompose" }
|
|
androidx-hilt-work = { group = "androidx.hilt", name = "hilt-work", version.ref = "hiltNavigationCompose" }
|
|
androidx-hilt-compiler = { group = "androidx.hilt", name = "hilt-compiler", version.ref = "hiltNavigationCompose" }
|
|
|
|
# Room (local cache)
|
|
androidx-room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "room" }
|
|
androidx-room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room" }
|
|
androidx-room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" }
|
|
# SQLCipher — opt-in at-rest encryption of the Room cache.
|
|
sqlcipher-android = { group = "net.zetetic", name = "sqlcipher-android", version.ref = "sqlcipher" }
|
|
|
|
# DataStore (settings) / WorkManager (sync) — wired in later increments
|
|
androidx-datastore-preferences = { group = "androidx.datastore", name = "datastore-preferences", version.ref = "datastore" }
|
|
androidx-work-runtime-ktx = { group = "androidx.work", name = "work-runtime-ktx", version.ref = "work" }
|
|
|
|
# Coroutines
|
|
kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "coroutines" }
|
|
kotlinx-coroutines-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "coroutines" }
|
|
|
|
# Email transport / OAuth — wired in later increments
|
|
appauth = { group = "net.openid", name = "appauth", version.ref = "appauth" }
|
|
angus-mail = { group = "org.eclipse.angus", name = "angus-mail", version.ref = "angusMail" }
|
|
|
|
# Test
|
|
junit = { group = "junit", name = "junit", version.ref = "junit" }
|
|
kotlin-test = { group = "org.jetbrains.kotlin", name = "kotlin-test", version.ref = "kotlin" }
|
|
turbine = { group = "app.cash.turbine", name = "turbine", version.ref = "turbine" }
|
|
mockk = { group = "io.mockk", name = "mockk", version.ref = "mockk" }
|
|
greenmail = { group = "com.icegreen", name = "greenmail", version.ref = "greenmail" }
|
|
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidxJunit" }
|
|
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espresso" }
|
|
androidx-espresso-intents = { group = "androidx.test.espresso", name = "espresso-intents", version.ref = "espresso" }
|
|
|
|
[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" }
|
|
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
|
|
hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }
|
|
ktlint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlint" }
|
|
detekt = { id = "dev.detekt", version.ref = "detekt" }
|