überarbeiten der datenbank anzeige

This commit is contained in:
oxidiert
2025-09-23 15:17:34 +02:00
parent 8dc9be20a4
commit 91f6f77b73
3 changed files with 58 additions and 65 deletions

View File

@ -19,7 +19,6 @@ class DatabaseButtonHandler(
private val uiScope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
private val tag = "DatabaseButtonHandler"
// Services (wie bei dir)
private val headerRepo = HeaderOrderRepository(activity)
private val exporter = ExcelExportService(activity, headerRepo)
@ -34,16 +33,15 @@ class DatabaseButtonHandler(
private fun openDatabaseScreen() {
activity.setContentView(R.layout.database_screen)
val lang = safeLang() // ✨
val lang = safeLang()
val titleTv: TextView = requireView(R.id.title, "title") // ✨
val titleTv: TextView = requireView(R.id.title, "title")
val table: TableLayout = requireView(R.id.tableClients, "tableClients")
val progress: ProgressBar = requireView(R.id.progressBar, "progressBar")
val emptyView: TextView = requireView(R.id.emptyView, "emptyView")
val backButton: Button = requireView(R.id.backButton, "backButton")
val btnDownloadHeader: Button = requireView(R.id.btnDownloadHeader, "btnDownloadHeader")
// ✨ statische Texte lokalisieren
titleTv.text = t(lang, "database_clients_title") ?: "Datenbank Clients"
emptyView.text = t(lang, "no_clients_available") ?: "Keine Clients vorhanden."
backButton.text = t(lang, "previous") ?: "Zurück"
@ -56,7 +54,6 @@ class DatabaseButtonHandler(
emptyView.visibility = View.GONE
table.removeAllViews()
// ✨ Spaltenkopf lokalisieren
addHeaderRow(table, listOf("#", t(lang, "client_code") ?: "Client-Code"))
uiScope.launch {
@ -91,7 +88,7 @@ class DatabaseButtonHandler(
val savedUri = exporter.exportHeadersForAllClients()
progress.visibility = View.GONE
val lang = safeLang() // ✨
val lang = safeLang()
if (savedUri != null) {
Toast.makeText(
activity,
@ -115,7 +112,7 @@ class DatabaseButtonHandler(
private fun openClientOverviewScreen(clientCode: String) {
activity.setContentView(R.layout.client_overview_screen)
val lang = safeLang() // ✨
val lang = safeLang()
val title: TextView = requireView(R.id.titleClientOverview, "titleClientOverview")
val tableQ: TableLayout = requireView(R.id.tableQuestionnaires, "tableQuestionnaires")
@ -126,7 +123,6 @@ class DatabaseButtonHandler(
val headerLabel: TextView = requireView(R.id.headerLabel, "headerLabel")
val tableOrdered: TableLayout = requireView(R.id.tableOrdered, "tableOrdered")
// ✨
title.text = "${t(lang, "client") ?: "Client"}: $clientCode ${t(lang, "questionnaires") ?: "Fragebögen"}"
headerLabel.text = t(lang, "headers") ?: "header"
backButton.text = t(lang, "previous") ?: "Zurück"
@ -137,7 +133,6 @@ class DatabaseButtonHandler(
tableQ.removeAllViews()
tableOrdered.removeAllViews()
// ✨ Tabellenköpfe lokalisieren
addHeaderRow(
tableQ,
listOf("#", t(lang, "questionnaire_id") ?: "Fragebogen-ID", t(lang, "status") ?: "Status")
@ -149,46 +144,53 @@ class DatabaseButtonHandler(
uiScope.launch {
val result = withContext(Dispatchers.IO) {
val allQuestionnaires = MyApp.database.questionnaireDao().getAll()
val completedForClient = MyApp.database.completedQuestionnaireDao().getAllForClient(clientCode)
val allAnswersForClient = MyApp.database.answerDao().getAnswersForClient(clientCode)
Triple(allQuestionnaires, completedForClient, allAnswersForClient)
val allQuestionnairesDb = MyApp.database.questionnaireDao().getAll()
val completedForClient = MyApp.database.completedQuestionnaireDao().getAllForClient(clientCode)
val allAnswersForClient = MyApp.database.answerDao().getAnswersForClient(clientCode)
Triple(allQuestionnairesDb, completedForClient, allAnswersForClient)
}
// IDs aus der JSON-Reihenfolge lesen (alle, die es geben soll)
val idsFromAssets: List<String> = loadQuestionnaireIdsFromAssets()
progress.visibility = View.GONE
val allQuestionnaires: List<Questionnaire> = result.first
val dbQuestionnaires: List<Questionnaire> = result.first
val completedForClient = result.second
val allAnswersForClient = result.third
if (allQuestionnaires.isEmpty()) {
// Vereinigung: alles was in JSON steht + alles was in der DB existiert
val allIds: List<String> =
(idsFromAssets + dbQuestionnaires.map { it.id }).distinct()
if (allIds.isEmpty()) {
emptyView.text = t(lang, "no_questionnaires") ?: "Keine Fragebögen vorhanden."
emptyView.visibility = View.VISIBLE
}
val statusMap = completedForClient.associate { it.questionnaireId to it.isDone }
val questionnaireIdSet = allQuestionnaires.map { it.id }.toSet()
val questionnaireIdSet = allIds.toSet() // für die zweite Tabelle
val answerMap = allAnswersForClient.associate { it.questionId to it.answerValue }
// Tabelle 1 (Status)
allQuestionnaires
.sortedWith(compareBy({ extractQuestionnaireNumber(it.id) ?: Int.MAX_VALUE }, { it.id }))
.forEachIndexed { idx, q ->
val isDone = statusMap[q.id] ?: false
// Tabelle 1 (Status) JETZT mit allen IDs
allIds
.sortedWith(compareBy({ extractQuestionnaireNumber(it) ?: Int.MAX_VALUE }, { it }))
.forEachIndexed { idx, qid ->
val isDone = statusMap[qid] ?: false
val statusText = if (isDone) "" else ""
val statusTextColor = if (isDone) 0xFF4CAF50.toInt() else 0xFFF44336.toInt()
if (isDone) {
addClickableRow(
table = tableQ,
cells = listOf((idx + 1).toString(), q.id, statusText),
onClick = { openQuestionnaireDetailScreen(clientCode, q.id) },
cells = listOf((idx + 1).toString(), qid, statusText),
onClick = { openQuestionnaireDetailScreen(clientCode, qid) },
colorOverrides = mapOf(2 to statusTextColor)
)
} else {
addDisabledRow(
table = tableQ,
cells = listOf((idx + 1).toString(), q.id, statusText),
cells = listOf((idx + 1).toString(), qid, statusText),
colorOverrides = mapOf(2 to statusTextColor)
)
}
@ -219,7 +221,7 @@ class DatabaseButtonHandler(
rowBgColor = if (raw == "None") lightRed else lightGreen
}
val display = localizeHeaderValue(id, raw, lang) // ✨
val display = localizeHeaderValue(id, raw, lang)
val cellBgOverrides =
if (cellBgForQuestionnaire != null)
@ -242,7 +244,7 @@ class DatabaseButtonHandler(
private fun openQuestionnaireDetailScreen(clientCode: String, questionnaireId: String) {
activity.setContentView(R.layout.questionnaire_detail_screen)
val lang = safeLang() // ✨
val lang = safeLang()
val title: TextView = requireView(R.id.titleQuestionnaireDetail, "titleQuestionnaireDetail")
val table: TableLayout = requireView(R.id.tableQA, "tableQA")
@ -250,7 +252,6 @@ class DatabaseButtonHandler(
val emptyView: TextView = requireView(R.id.emptyViewQA, "emptyViewQA")
val backButton: Button = requireView(R.id.backButtonQA, "backButtonQA")
// ✨ Titel + Back + Empty übersetzen
title.text = "${t(lang, "client") ?: "Client"}: $clientCode ${t(lang, "questionnaire") ?: "Fragebogen"}: $questionnaireId"
backButton.text = t(lang, "previous") ?: "Zurück"
emptyView.text = t(lang, "no_questions_available") ?: "Keine Fragen vorhanden."
@ -260,7 +261,6 @@ class DatabaseButtonHandler(
emptyView.visibility = View.GONE
table.removeAllViews()
// ✨ Kopf: # | Frage | Antwort
addHeaderRow(table, listOf("#", t(lang, "question") ?: "Frage", t(lang, "answer") ?: "Antwort"))
uiScope.launch {
@ -281,17 +281,17 @@ class DatabaseButtonHandler(
val answerMap = answersForClient.associate { it.questionId to it.answerValue }
questions.forEachIndexed { idx, q: Question ->
val baseId = q.questionId.substringAfterLast('-', q.questionId) // z.B. consent_signed, gender_male
val qText = localizeQuestionLabel(q.questionId, q.question, lang) // ✨
val baseId = q.questionId.substringAfterLast('-', q.questionId)
val qText = localizeQuestionLabel(q.questionId, q.question, lang)
val raw = answerMap[q.questionId]?.takeIf { it.isNotBlank() } ?: ""
val aText = localizeAnswerValue(baseId, raw, lang) // ✨
val aText = localizeAnswerValue(baseId, raw, lang)
addRow(table, listOf((idx + 1).toString(), qText, aText))
}
}
}
// ---------------------------
// Lokalisierungshilfen (Anzeige)
// Hilfen
// ---------------------------
private fun safeLang(): String = try { languageIDProvider() } catch (_: Exception) { "GERMAN" }
@ -307,38 +307,27 @@ class DatabaseButtonHandler(
return if (out.equals(key, true) || out.isBlank()) null else out
}
// ✨ Frage-Label für die UI
private fun localizeQuestionLabel(questionId: String, fallbackQuestionText: String?, lang: String): String {
val field = questionId.substringAfterLast('-', questionId)
t(lang, field)?.let { return it } // z.B. consent_instruction
t(lang, questionId)?.let { return it } // kompletter key
t(lang, field)?.let { return it }
t(lang, questionId)?.let { return it }
fallbackQuestionText?.takeIf { it.isNotBlank() }?.let { return it }
return field.replace('_', ' ').replaceFirstChar { it.titlecase() }
}
// ✨ Antwort-Wert für die UI
private fun localizeAnswerValue(fieldId: String, raw: String, lang: String): String {
// Zahlen/Datum/Strich beibehalten
if (raw == "") return raw
if (raw.matches(Regex("^\\d{1,4}([./-]\\d{1,2}([./-]\\d{1,4})?)?\$"))) return raw
// 1) direkter Key
t(lang, raw)?.let { return it }
// 2) normalisiert
val norm = raw.lowercase().replace(Regex("[^a-z0-9]+"), "_").trim('_')
if (norm.isNotBlank()) t(lang, norm)?.let { return it }
// 3) kombiniere Feld + Wert (häufiges Muster)
if (norm.isNotBlank()) {
t(lang, "${fieldId}_$norm")?.let { return it }
t(lang, "${fieldId}-${norm}")?.let { return it }
}
// Klammern entfernen, falls aus LanguageManager so geliefert
return stripBrackets(raw)
}
// ---------------------------
// Anzeige-Helfer
// ---------------------------
private fun addHeaderRow(table: TableLayout, labels: List<String>) {
val row = TableRow(activity)
labels.forEach { label -> row.addView(makeHeaderCell(label)) }
@ -442,7 +431,6 @@ class DatabaseButtonHandler(
return m?.groupValues?.get(1)?.toIntOrNull()
}
// ✨ alte localizeHeaderValue erweitert: nimmt jetzt lang mit
private fun localizeHeaderValue(id: String, raw: String, lang: String): String {
if (id == "client_code") return raw
@ -457,4 +445,17 @@ class DatabaseButtonHandler(
for (k in candidates) t(lang, k)?.let { return it }
return stripBrackets(raw)
}
/** Lädt alle Fragebogen-IDs aus questionnaire_order.json (file ohne .json). */
private fun loadQuestionnaireIdsFromAssets(): List<String> = try {
val input = activity.assets.open("questionnaire_order.json")
val json = input.bufferedReader().use { it.readText() }
val arr = JSONArray(json)
(0 until arr.length()).mapNotNull { i ->
val obj = arr.optJSONObject(i)
obj?.optString("file")?.removeSuffix(".json")
}
} catch (_: Exception) {
emptyList()
}
}

View File

@ -649,8 +649,8 @@ object LanguageManager {
"please_client_code" to "Please enter client code",
"no_profile" to "This client is not yet part of the database",
"questionnaires_finished" to "All questionnaires have been completed for this client!",
"edit" to "Bearbeiten",
"save" to "Speichern",
"edit" to "Edit",
"save" to "Save",
"upload" to "Upload",
"download" to "Download",
"database" to "Database",