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:
parent
90eb15ca0b
commit
80c8c4788a
9 changed files with 52 additions and 27 deletions
|
|
@ -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")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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() &&
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,21 +1,37 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- A capsule at 45°: two half-pill rounded shapes. Placeholder-quality, but ours. -->
|
||||
<!-- A capsule in a hurry: stadium-shaped pill flying up-right at 45°, with
|
||||
motion lines trailing — «med det samme» as an icon. Safe zone: center 66
|
||||
of the 108 viewport. -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<group
|
||||
android:rotation="45"
|
||||
android:rotation="-45"
|
||||
android:pivotX="54"
|
||||
android:pivotY="54">
|
||||
<!-- motion lines trailing behind (left of) the capsule -->
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M42,30 h24 a12,12 0 0 1 12,12 v0 h-48 v0 a12,12 0 0 1 12,-12 z"
|
||||
android:strokeWidth="0" />
|
||||
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" />
|
||||
<path
|
||||
android:fillColor="#59FFFFFF"
|
||||
android:pathData="M14,43.5 h10 a2.5,2.5 0 0 1 0,5 h-10 a2.5,2.5 0 0 1 0,-5 z" />
|
||||
<path
|
||||
android:fillColor="#59FFFFFF"
|
||||
android:pathData="M14,59.5 h10 a2.5,2.5 0 0 1 0,5 h-10 a2.5,2.5 0 0 1 0,-5 z" />
|
||||
<!-- capsule: full stadium in pale green -->
|
||||
<path
|
||||
android:fillColor="#A5D6A7"
|
||||
android:pathData="M30,42 h48 v24 a12,12 0 0 1 -12,12 h-24 a12,12 0 0 1 -12,-12 z"
|
||||
android:strokeWidth="0" />
|
||||
android:pathData="M50,43 h26 a11,11 0 0 1 0,22 h-26 a11,11 0 0 1 0,-22 z" />
|
||||
<!-- leading half in white -->
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M63,43 h13 a11,11 0 0 1 0,22 h-13 z" />
|
||||
<!-- highlight on the leading cap -->
|
||||
<path
|
||||
android:fillColor="#33FFFFFF"
|
||||
android:pathData="M72,46.5 a3,3 0 1 1 0,6 a3,3 0 1 1 0,-6 z" />
|
||||
</group>
|
||||
</vector>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- minSdk 26 = adaptive icons everywhere; no legacy PNG densities needed. -->
|
||||
<!-- minSdk 26 = adaptive icons everywhere (anydpi, no -v26 qualifier needed). -->
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
|
|
@ -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 <kotlin>-<ksp> pairs)
|
||||
composeBom = "2026.05.00"
|
||||
composeBom = "2026.05.01"
|
||||
activityCompose = "1.13.0"
|
||||
coreKtx = "1.19.0"
|
||||
lifecycle = "2.10.0"
|
||||
|
|
|
|||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue