Form icons replace letter avatars in med and lager lists

Seven hand-drawn 24dp vectors (tablet/capsule/liquid/injection/drops/
spray/other) so what-you-take reads at a glance. Icons are decorative;
the rows' merged contentDescription now includes the form label so
TalkBack gains the same information the icon conveys visually.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Ole-Morten Duesund 2026-06-11 16:50:20 +02:00
commit 747a87a570
10 changed files with 111 additions and 9 deletions

View file

@ -84,11 +84,11 @@ fun InventoryScreen(nav: Nav) {
.clickable { nav.push(Screen.ItemEdit(item.id)) }
.semantics(mergeDescendants = true) {
contentDescription =
"${item.name} ${item.strength}, ${ScheduleText.amountText(item.stockUnits, item.unit)} på lager. Trykk for å redigere."
"${item.name} ${item.strength}, ${FORM_LABELS[item.form]}, ${ScheduleText.amountText(item.stockUnits, item.unit)} på lager. Trykk for å redigere."
},
) {
Row(Modifier.padding(12.dp), verticalAlignment = Alignment.CenterVertically) {
LetterAvatar(item.name)
FormAvatar(item.form)
Column(Modifier.padding(start = 12.dp).weight(1f)) {
Text("${item.name} ${item.strength}".trim(), style = MaterialTheme.typography.titleMedium)
Text(

View file

@ -73,9 +73,23 @@ fun guessForm(festForm: String): MedForm = when {
fun parseAmount(s: String): Double? = s.trim().replace(',', '.').toDoubleOrNull()
/** Tonal circle with the preparation's initial — cheap visual anchor in lists. */
/** Pharmaceutical-form icon for list rows. */
fun iconForForm(form: MedForm): Int = when (form) {
MedForm.TABLET -> no.naiv.meddetsamme.R.drawable.ic_form_tablet
MedForm.CAPSULE -> no.naiv.meddetsamme.R.drawable.ic_form_capsule
MedForm.LIQUID -> no.naiv.meddetsamme.R.drawable.ic_form_liquid
MedForm.INJECTION -> no.naiv.meddetsamme.R.drawable.ic_form_injection
MedForm.DROPS -> no.naiv.meddetsamme.R.drawable.ic_form_drops
MedForm.SPRAY -> no.naiv.meddetsamme.R.drawable.ic_form_spray
MedForm.OTHER -> no.naiv.meddetsamme.R.drawable.ic_form_other
}
/**
* Tonal circle with the form's icon what-am-I-taking at a glance.
* Decorative: rows carry a full merged contentDescription including the form.
*/
@Composable
fun LetterAvatar(name: String) {
fun FormAvatar(form: MedForm) {
androidx.compose.material3.Surface(
shape = androidx.compose.foundation.shape.CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
@ -83,9 +97,10 @@ fun LetterAvatar(name: String) {
modifier = Modifier.size(40.dp),
) {
Box(contentAlignment = Alignment.Center) {
Text(
name.firstOrNull()?.uppercase() ?: "?",
style = MaterialTheme.typography.titleMedium,
androidx.compose.material3.Icon(
androidx.compose.ui.res.painterResource(iconForForm(form)),
contentDescription = null,
modifier = Modifier.size(22.dp),
)
}
}

View file

@ -80,11 +80,11 @@ fun MedListScreen(nav: Nav) {
.clickable { nav.push(Screen.MedEdit(med.med.id)) }
.semantics(mergeDescendants = true) {
contentDescription =
"${med.displayName}, lager ${ScheduleText.amountText(med.item.stockUnits, med.item.unit)}. Trykk for å redigere."
"${med.displayName}, ${FORM_LABELS[med.item.form]}, lager ${ScheduleText.amountText(med.item.stockUnits, med.item.unit)}. Trykk for å redigere."
},
) {
Row(Modifier.padding(12.dp), verticalAlignment = Alignment.CenterVertically) {
LetterAvatar(med.item.name)
FormAvatar(med.item.form)
Column(Modifier.padding(start = 12.dp).weight(1f)) {
Text(med.displayName, style = MaterialTheme.typography.titleMedium)
Text(

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Diagonal capsule, half filled -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:height="24dp"
android:viewportWidth="24" android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="M4.22,11.29l7.07,-7.07c2.34,-2.34 6.14,-2.34 8.49,0s2.34,6.14 0,8.49l-7.07,7.07c-2.34,2.34 -6.14,2.34 -8.49,0S1.88,13.64 4.22,11.29zM5.64,12.71c-1.56,1.56 -1.56,4.09 0,5.66s4.09,1.56 5.66,0l2.83,-2.83 -5.66,-5.66L5.64,12.71z" />
</vector>

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Drop -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:height="24dp"
android:viewportWidth="24" android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="M12,2.5 C12,2.5 5.5,10 5.5,14.6 C5.5,18.2 8.4,21 12,21 s6.5,-2.8 6.5,-6.4 C18.5,10 12,2.5 12,2.5z M12,19 c-2.5,0 -4.5,-2 -4.5,-4.4 c0,-0.5 0.1,-1 0.3,-1.6 h8.4 c0.2,0.6 0.3,1.1 0.3,1.6 C16.5,17 14.5,19 12,19z" />
</vector>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Syringe at 45° -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:height="24dp"
android:viewportWidth="24" android:viewportHeight="24">
<path
android:strokeColor="#FF000000" android:strokeWidth="2"
android:pathData="M20,4 l-2.5,2.5 M21.5,8 l-5.5,-5.5" />
<path
android:strokeColor="#FF000000" android:strokeWidth="2" android:fillColor="#00000000"
android:pathData="M14,5.5 l4.5,4.5 -8.5,8.5 -4.5,-4.5 z" />
<path
android:strokeColor="#FF000000" android:strokeWidth="2"
android:pathData="M7,14.5 l-2.5,2.5 M9.5,17 l-2.5,2.5 M4.5,17 l-1.5,1.5 M9,12.5 l2,2 M11.5,10 l2,2" />
</vector>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Medicine bottle with cap and fill line -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:height="24dp"
android:viewportWidth="24" android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="M9,2 h6 v3 h-6 z" />
<path
android:strokeColor="#FF000000" android:strokeWidth="2" android:fillColor="#00000000"
android:pathData="M9,7 h6 l1.5,3 v10 a1,1 0 0 1 -1,1 h-7 a1,1 0 0 1 -1,-1 v-10 z" />
<path
android:fillColor="#FF000000"
android:pathData="M8.6,14 h6.8 v6 a0.4,0.4 0 0 1 -0.4,0.4 h-6 a0.4,0.4 0 0 1 -0.4,-0.4 z" />
</vector>

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Medical cross in circle -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:height="24dp"
android:viewportWidth="24" android:viewportHeight="24">
<path
android:strokeColor="#FF000000" android:strokeWidth="2" android:fillColor="#00000000"
android:pathData="M12,12 m-9,0 a9,9 0 1,0 18,0 a9,9 0 1,0 -18,0" />
<path
android:fillColor="#FF000000"
android:pathData="M10.75,7 h2.5 v3.75 H17 v2.5 h-3.75 V17 h-2.5 v-3.75 H7 v-2.5 h3.75 z" />
</vector>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Spray bottle with mist dots -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:height="24dp"
android:viewportWidth="24" android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="M10,3 h5 v2.5 h-5 z M11.5,6.5 h2 v2.5 h-2 z" />
<path
android:strokeColor="#FF000000" android:strokeWidth="2" android:fillColor="#00000000"
android:pathData="M10,10 h5 a1.5,1.5 0 0 1 1.5,1.5 v8 a1.5,1.5 0 0 1 -1.5,1.5 h-5 a1.5,1.5 0 0 1 -1.5,-1.5 v-8 a1.5,1.5 0 0 1 1.5,-1.5 z" />
<path
android:fillColor="#FF000000"
android:pathData="M5.5,3 m-1.2,0 a1.2,1.2 0 1,0 2.4,0 a1.2,1.2 0 1,0 -2.4,0 M3.5,7 m-1.2,0 a1.2,1.2 0 1,0 2.4,0 a1.2,1.2 0 1,0 -2.4,0 M7,6.2 m-1,0 a1,1 0 1,0 2,0 a1,1 0 1,0 -2,0" />
</vector>

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Round tablet with score line -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:height="24dp"
android:viewportWidth="24" android:viewportHeight="24">
<path
android:strokeColor="#FF000000" android:strokeWidth="2" android:fillColor="#00000000"
android:pathData="M12,12 m-8,0 a8,8 0 1,0 16,0 a8,8 0 1,0 -16,0" />
<path
android:strokeColor="#FF000000" android:strokeWidth="2"
android:pathData="M5.5,12 h13" />
</vector>