fixed online connection error and class scale question bug

This commit is contained in:
oxidiert
2026-02-23 18:20:21 +01:00
parent d30c94beeb
commit 07b7b3dc1b
2 changed files with 61 additions and 21 deletions

1
.idea/misc.xml generated
View File

@ -1,4 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">

View File

@ -9,11 +9,10 @@ import androidx.core.widget.TextViewCompat
import kotlinx.coroutines.*
/*
Zweck:
- Stellt eine „Glas-Skala“-Frage dar, bei der pro Symptom (Zeile) genau eine von fünf Antwortstufen gewählt wird: never / little / moderate / much / extreme.
- Die Stufen werden sowohl als RadioButtons als auch über eine feste Icon-Leiste visualisiert.
- „Glas-Skala“-Frage: pro Symptom (Zeile) genau eine von fünf Stufen.
- Stufen als RadioButtons (clickbar) + Icon-Header.
- FIX: Pro Zeile wird Single-Select erzwungen (auch im Bearbeiten-Modus / Restore).
*/
class HandlerGlassScaleQuestion(
@ -54,6 +53,9 @@ class HandlerGlassScaleQuestion(
"extreme_glass" to R.drawable.ic_glass_4
)
// Damit wir beim programmatic-check keine Endlosschleifen triggern
private var suppressRowListener: Boolean = false
override fun bind(layout: View, question: QuestionItem) {
if (question !is QuestionItem.GlassScaleQuestion) return
this.layout = layout
@ -68,12 +70,13 @@ class HandlerGlassScaleQuestion(
setTextSizePercentOfScreenHeight(titleTv, 0.03f)
setTextSizePercentOfScreenHeight(questionTv, 0.03f)
// feste Icon-Leiste
// Header Icons
val header = layout.findViewById<LinearLayout>(R.id.glass_header)
header.removeAllViews()
header.addView(Space(context).apply {
layoutParams = LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 4f)
})
val iconSizePx = (context.resources.displayMetrics.density * 36).toInt()
scaleLabels.forEach { labelKey ->
val cell = FrameLayout(context).apply {
@ -88,13 +91,12 @@ class HandlerGlassScaleQuestion(
cell.addView(img)
header.addView(cell)
}
//
val tableLayout = layout.findViewById<TableLayout>(R.id.glass_table)
tableLayout.removeAllViews()
addSymptomRows(tableLayout)
// ggf. Antworten aus DB wiederherstellen
// Restore aus DB (nur wenn noch nicht im answers)
val anySymptomNeedsRestore = question.symptoms.any { !answers.containsKey(it) }
if (anySymptomNeedsRestore) {
CoroutineScope(Dispatchers.IO).launch {
@ -104,21 +106,14 @@ class HandlerGlassScaleQuestion(
val answerMap = allAnswersForClient.associateBy({ it.questionId }, { it.answerValue })
withContext(Dispatchers.Main) {
val table = tableLayout
for ((index, symptomKey) in question.symptoms.withIndex()) {
val answerMapKey = "$questionnaireMeta-$symptomKey"
val dbAnswer = answerMap[answerMapKey]?.takeIf { it.isNotBlank() }?.trim()
if (!answers.containsKey(symptomKey) && !dbAnswer.isNullOrBlank()) {
if (index < table.childCount) {
val row = table.getChildAt(index) as? TableRow ?: continue
if (index < tableLayout.childCount) {
val row = tableLayout.getChildAt(index) as? TableRow ?: continue
val radioGroup = row.getChildAt(1) as? RadioGroup ?: continue
for (i in 0 until radioGroup.childCount) {
val rb = getRadioFromChild(radioGroup.getChildAt(i)) ?: continue
if ((rb.tag as? String)?.trim() == dbAnswer) {
rb.isChecked = true
break
}
}
setSingleSelection(radioGroup, dbAnswer) // <-- FIXED restore
answers[symptomKey] = dbAnswer
points.add(pointsMap[dbAnswer] ?: 0)
}
@ -165,30 +160,75 @@ class HandlerGlassScaleQuestion(
setPadding(0, 0, 0, 0)
}
// Build buttons
scaleLabels.forEach { labelKey ->
val cell = FrameLayout(context).apply {
layoutParams = RadioGroup.LayoutParams(0, RadioGroup.LayoutParams.WRAP_CONTENT, 1f)
}
val rb = RadioButton(context).apply {
tag = labelKey
id = View.generateViewId()
isChecked = savedLabel == labelKey
isChecked = false
setPadding(0, 0, 0, 0)
}
rb.layoutParams = FrameLayout.LayoutParams(
FrameLayout.LayoutParams.WRAP_CONTENT,
FrameLayout.LayoutParams.WRAP_CONTENT,
Gravity.CENTER
)
// <<< FIX: erzwinge pro Zeile genau eine Auswahl
rb.setOnCheckedChangeListener { buttonView, isChecked ->
if (suppressRowListener) return@setOnCheckedChangeListener
if (!isChecked) return@setOnCheckedChangeListener
val selectedLabel = buttonView.tag as? String ?: return@setOnCheckedChangeListener
// wenn einer checked -> alle anderen in dieser Row unchecken
suppressRowListener = true
try {
for (i in 0 until radioGroup.childCount) {
val other = getRadioFromChild(radioGroup.getChildAt(i)) ?: continue
if (other != buttonView) other.isChecked = false
}
} finally {
suppressRowListener = false
}
// Optional (wenn du willst): sofort im answers setzen (Edit-Mode fühlt sich dann "direkt" an)
answers[symptomKey] = selectedLabel
}
cell.addView(rb)
radioGroup.addView(cell)
}
// Restore aus answers (falls vorhanden)
if (!savedLabel.isNullOrBlank()) {
setSingleSelection(radioGroup, savedLabel)
}
row.addView(radioGroup)
table.addView(row)
}
}
/**
* Setzt in diesem Row-RadioGroup genau einen Wert aktiv und alle anderen aus.
*/
private fun setSingleSelection(radioGroup: RadioGroup, labelKey: String) {
suppressRowListener = true
try {
for (i in 0 until radioGroup.childCount) {
val rb = getRadioFromChild(radioGroup.getChildAt(i)) ?: continue
val tag = (rb.tag as? String)?.trim()
rb.isChecked = (tag == labelKey.trim())
}
} finally {
suppressRowListener = false
}
}
override fun validate(): Boolean {
val table = layout.findViewById<TableLayout>(R.id.glass_table)
@ -217,6 +257,7 @@ class HandlerGlassScaleQuestion(
val row = table.getChildAt(i) as TableRow
val symptomKey = question.symptoms[i]
val radioGroup = row.getChildAt(1) as RadioGroup
for (j in 0 until radioGroup.childCount) {
val rb = getRadioFromChild(radioGroup.getChildAt(j)) ?: continue
if (rb.isChecked) {