überarbeiten der datenbank anzeige
This commit is contained in:
@ -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 allQuestionnairesDb = MyApp.database.questionnaireDao().getAll()
|
||||
val completedForClient = MyApp.database.completedQuestionnaireDao().getAllForClient(clientCode)
|
||||
val allAnswersForClient = MyApp.database.answerDao().getAnswersForClient(clientCode)
|
||||
Triple(allQuestionnaires, completedForClient, allAnswersForClient)
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -15,26 +15,19 @@
|
||||
android:textSize="20sp"
|
||||
android:paddingBottom="8dp" />
|
||||
|
||||
<!-- Tabelle 1: Fragebögen (✓/✗) -->
|
||||
<!-- OBERTEIL: Alle Fragebögen vollständig (kein Weight, keine vertikale ScrollView) -->
|
||||
<HorizontalScrollView
|
||||
android:id="@+id/qsScroll"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:fillViewport="true"
|
||||
android:scrollbars="horizontal">
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:fillViewport="true"
|
||||
android:scrollbars="vertical">
|
||||
|
||||
<TableLayout
|
||||
android:id="@+id/tableQuestionnaires"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:stretchColumns="1" />
|
||||
</ScrollView>
|
||||
</HorizontalScrollView>
|
||||
|
||||
<TextView
|
||||
@ -54,7 +47,7 @@
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp" />
|
||||
|
||||
<!-- HEADER + Tabelle 2: geordnete IDs/Werte -->
|
||||
<!-- HEADER + Tabelle 2: Scrollbar bekommt den restlichen Platz -->
|
||||
<TextView
|
||||
android:id="@+id/headerLabel"
|
||||
android:layout_width="match_parent"
|
||||
@ -89,7 +82,6 @@
|
||||
<Button
|
||||
android:id="@+id/backButtonClient"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Zurück" />
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
Reference in New Issue
Block a user