diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 35aeb6a..62fad8c 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -31,8 +31,10 @@ android { applicationId = "no.naiv.meddetsamme" minSdk = 26 targetSdk = 35 - versionCode = 1 - versionName = "0.1.0" + // Bump both for every release installed on the phone — versionName for + // humans, versionCode so dumpsys/install history can tell builds apart. + versionCode = 2 + versionName = "0.2.0" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } @@ -67,6 +69,14 @@ android { compose = true } + lint { + // Deliberate decisions, not oversights — see CLAUDE.md: + // BatteryLife: decision #4, sideloaded app (Play policy n/a). + // OldTargetApi: targetSdk 35 is pinned by the brief. + // NewerVersionAvailable: Kotlin 2.4 is blocked until KSP supports it. + disable += listOf("BatteryLife", "OldTargetApi", "NewerVersionAvailable") + } + // MigrationTestHelper reads the exported schema JSONs as androidTest assets. sourceSets.getByName("androidTest").assets.srcDir("$projectDir/schemas") } diff --git a/app/src/main/java/no/naiv/meddetsamme/alarm/BatteryOptimization.kt b/app/src/main/java/no/naiv/meddetsamme/alarm/BatteryOptimization.kt index 577b07d..ee56c16 100644 --- a/app/src/main/java/no/naiv/meddetsamme/alarm/BatteryOptimization.kt +++ b/app/src/main/java/no/naiv/meddetsamme/alarm/BatteryOptimization.kt @@ -2,9 +2,9 @@ package no.naiv.meddetsamme.alarm import android.content.Context import android.content.Intent -import android.net.Uri import android.os.PowerManager import android.provider.Settings +import androidx.core.net.toUri /** * Battery-optimisation ("Doze whitelist") exemption — brief decision #4: the @@ -24,6 +24,6 @@ object BatteryOptimization { fun requestExemptionIntent(context: Context): Intent = Intent( Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, - Uri.parse("package:${context.packageName}"), + "package:${context.packageName}".toUri(), ) } diff --git a/app/src/main/java/no/naiv/meddetsamme/settings/SettingsStore.kt b/app/src/main/java/no/naiv/meddetsamme/settings/SettingsStore.kt index 3ccbd50..afb6fb3 100644 --- a/app/src/main/java/no/naiv/meddetsamme/settings/SettingsStore.kt +++ b/app/src/main/java/no/naiv/meddetsamme/settings/SettingsStore.kt @@ -4,6 +4,7 @@ import android.content.Context import android.security.keystore.KeyGenParameterSpec import android.security.keystore.KeyProperties import android.util.Base64 +import androidx.core.content.edit import java.security.KeyStore import javax.crypto.Cipher import javax.crypto.KeyGenerator @@ -37,22 +38,22 @@ class SettingsStore(context: Context) { /** Non-secret flags can live in plaintext prefs. */ var batteryPromptShown: Boolean get() = prefs.getBoolean("battery_prompt_shown", false) - set(v) = prefs.edit().putBoolean("battery_prompt_shown", v).apply() + set(v) = prefs.edit { putBoolean("battery_prompt_shown", v) } /** FEST dataset URL — not a secret, plaintext pref. */ var festUrl: String? get() = prefs.getString("fest_url", null) - set(v) = prefs.edit().putString("fest_url", v).apply() + set(v) = prefs.edit { putString("fest_url", v) } /** One-time "backup isn't set up" card on the Today screen. */ var backupNudgeDismissed: Boolean get() = prefs.getBoolean("backup_nudge_dismissed", false) - set(v) = prefs.edit().putBoolean("backup_nudge_dismissed", v).apply() + set(v) = prefs.edit { putBoolean("backup_nudge_dismissed", v) } /** Daily low-stock/rx check time, minutes after midnight. Default 10:00. */ var supplyCheckMinuteOfDay: Int get() = prefs.getInt("supply_check_minute", 600) - set(v) = prefs.edit().putInt("supply_check_minute", v.coerceIn(0, 1439)).apply() + set(v) = prefs.edit { putInt("supply_check_minute", v.coerceIn(0, 1439)) } val isBackupConfigured: Boolean get() = !s3Endpoint.isNullOrBlank() && !s3Bucket.isNullOrBlank() && diff --git a/app/src/main/java/no/naiv/meddetsamme/ui/ItemForm.kt b/app/src/main/java/no/naiv/meddetsamme/ui/ItemForm.kt index 69b4e68..d22eca1 100644 --- a/app/src/main/java/no/naiv/meddetsamme/ui/ItemForm.kt +++ b/app/src/main/java/no/naiv/meddetsamme/ui/ItemForm.kt @@ -32,6 +32,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp +import androidx.core.net.toUri import java.time.LocalDate import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -111,14 +112,11 @@ fun FormAvatar(form: MedForm) { * reading only. Decision #8 bans Felleskatalogen as a DATA source (licensed * editorial content, no API); pointing the human at their website is fine. */ -fun felleskatalogenIntent(name: String): android.content.Intent = - android.content.Intent( - android.content.Intent.ACTION_VIEW, - android.net.Uri.parse( - "https://www.felleskatalogen.no/medisin/sok?sokord=" + - java.net.URLEncoder.encode(name.trim(), "UTF-8"), - ), - ) +fun felleskatalogenIntent(name: String): android.content.Intent { + val url = "https://www.felleskatalogen.no/medisin/sok?sokord=" + + java.net.URLEncoder.encode(name.trim(), "UTF-8") + return android.content.Intent(android.content.Intent.ACTION_VIEW, url.toUri()) +} /** * State + validation for an [InventoryItem] form — shared between the diff --git a/app/src/main/java/no/naiv/meddetsamme/ui/SummaryPreviewScreen.kt b/app/src/main/java/no/naiv/meddetsamme/ui/SummaryPreviewScreen.kt index f1fe7fb..06a07af 100644 --- a/app/src/main/java/no/naiv/meddetsamme/ui/SummaryPreviewScreen.kt +++ b/app/src/main/java/no/naiv/meddetsamme/ui/SummaryPreviewScreen.kt @@ -64,7 +64,7 @@ fun SummaryPreviewScreen(nav: Nav) { renderer.openPage(i).use { page -> // 2x point size — crisp on phone screens without // burning memory on huge bitmaps. - val bmp = Bitmap.createBitmap(page.width * 2, page.height * 2, Bitmap.Config.ARGB_8888) + val bmp = androidx.core.graphics.createBitmap(page.width * 2, page.height * 2) bmp.eraseColor(android.graphics.Color.WHITE) page.render(bmp, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY) rendered += bmp diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml index abb1f8c..35e4638 100644 --- a/app/src/main/res/drawable/ic_launcher_foreground.xml +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -1,21 +1,37 @@ - + + + android:fillColor="#80FFFFFF" + android:pathData="M18,51.5 h12 a2.5,2.5 0 0 1 0,5 h-12 a2.5,2.5 0 0 1 0,-5 z" /> + + + + android:pathData="M50,43 h26 a11,11 0 0 1 0,22 h-26 a11,11 0 0 1 0,-22 z" /> + + + + diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi/ic_launcher.xml similarity index 80% rename from app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml rename to app/src/main/res/mipmap-anydpi/ic_launcher.xml index 5d589d0..adb9f2d 100644 --- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ b/app/src/main/res/mipmap-anydpi/ic_launcher.xml @@ -1,5 +1,5 @@ - + diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 91886d4..57ac4d5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -6,7 +6,7 @@ agp = "9.2.1" kotlin = "2.3.10" ksp = "2.3.9" # KSP versioning decoupled from Kotlin since 2.3.0 (no more - pairs) -composeBom = "2026.05.00" +composeBom = "2026.05.01" activityCompose = "1.13.0" coreKtx = "1.19.0" lifecycle = "2.10.0" diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index c61a118..5dd3c01 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME