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