New launcher icon, version 0.2.0, lint cleanup

Icon: a capsule in a hurry — stadium pill at 45° with motion lines
trailing, «med det samme» as imagery. versionCode 2 / versionName 0.2.0
with a bump-on-release note. Lint: KTX conversions (prefs.edit{},
toUri, createBitmap), mipmap-anydpi-v26 merged into mipmap-anydpi
(minSdk 26 makes the qualifier dead weight), compose-bom 2026.05.01,
Gradle wrapper 9.5.1, and the three deliberate-decision warnings
(BatteryLife/OldTargetApi/NewerVersionAvailable) disabled with
documented reasons. Lint now runs clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Ole-Morten Duesund 2026-06-11 17:55:06 +02:00
commit 80c8c4788a
9 changed files with 52 additions and 27 deletions

View file

@ -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(),
)
}

View file

@ -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() &&

View file

@ -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

View file

@ -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