fixed wrong loading bug, fixed editing bug
This commit is contained in:
@ -14,7 +14,9 @@ class EditButtonHandler(
|
||||
private val questionnaireFiles: Map<Button, String>,
|
||||
private val buttonPoints: MutableMap<String, Int>,
|
||||
private val updateButtonTexts: () -> Unit,
|
||||
private val setButtonsEnabled: (List<Button>) -> Unit
|
||||
private val setButtonsEnabled: (List<Button>) -> Unit,
|
||||
// vor "Bearbeiten" ggf. Laden anstoßen
|
||||
private val triggerLoad: () -> Unit
|
||||
) {
|
||||
|
||||
fun setup() {
|
||||
@ -23,18 +25,38 @@ class EditButtonHandler(
|
||||
}
|
||||
|
||||
private fun handleEditButtonClick() {
|
||||
val clientCode = editText.text.toString().trim()
|
||||
if (clientCode.isBlank()) {
|
||||
val typed = editText.text.toString().trim()
|
||||
val desiredCode = when {
|
||||
typed.isNotBlank() -> typed
|
||||
!GlobalValues.LOADED_CLIENT_CODE.isNullOrBlank() -> GlobalValues.LOADED_CLIENT_CODE!!
|
||||
else -> ""
|
||||
}
|
||||
|
||||
if (desiredCode.isBlank()) {
|
||||
val message = LanguageManager.getText(languageIDProvider(), "please_client_code")
|
||||
Toast.makeText(activity, message, Toast.LENGTH_SHORT).show()
|
||||
return
|
||||
}
|
||||
|
||||
GlobalValues.LAST_CLIENT_CODE = clientCode
|
||||
// Nutzerwunsch merken (info)
|
||||
GlobalValues.LAST_CLIENT_CODE = desiredCode
|
||||
|
||||
// Nur laden, wenn noch nicht/anders geladen
|
||||
val needLoad = GlobalValues.LOADED_CLIENT_CODE?.equals(desiredCode) != true
|
||||
if (needLoad) triggerLoad()
|
||||
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val loadedOk = waitUntilClientLoaded(desiredCode, timeoutMs = 2500, stepMs = 50)
|
||||
if (!loadedOk) {
|
||||
withContext(Dispatchers.Main) {
|
||||
Toast.makeText(activity, "Bitte den Klienten über \"Laden\" öffnen.", Toast.LENGTH_LONG).show()
|
||||
}
|
||||
return@launch
|
||||
}
|
||||
|
||||
// Ab hier: geladen → Bearbeiten-Logik
|
||||
val completedEntries: List<CompletedQuestionnaire> =
|
||||
MyApp.database.completedQuestionnaireDao().getAllForClient(clientCode)
|
||||
MyApp.database.completedQuestionnaireDao().getAllForClient(desiredCode)
|
||||
|
||||
val completedFiles = completedEntries
|
||||
.filter { it.isDone }
|
||||
@ -58,4 +80,17 @@ class EditButtonHandler(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun waitUntilClientLoaded(expectedCode: String, timeoutMs: Long, stepMs: Long): Boolean {
|
||||
// sofort ok, wenn bereits korrekt geladen
|
||||
if (GlobalValues.LOADED_CLIENT_CODE?.equals(expectedCode) == true) return true
|
||||
|
||||
var waited = 0L
|
||||
while (waited < timeoutMs) {
|
||||
delay(stepMs)
|
||||
waited += stepMs
|
||||
if (GlobalValues.LOADED_CLIENT_CODE?.equals(expectedCode) == true) return true
|
||||
}
|
||||
return GlobalValues.LOADED_CLIENT_CODE?.equals(expectedCode) == true
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,50 +26,39 @@ class HandlerClientCoachCode(
|
||||
this.layout = layout
|
||||
this.question = question
|
||||
|
||||
// Bind UI components
|
||||
val clientCodeField = layout.findViewById<EditText>(R.id.client_code)
|
||||
val coachCodeField = layout.findViewById<EditText>(R.id.coach_code)
|
||||
val questionTextView = layout.findViewById<TextView>(R.id.question)
|
||||
val titleTextView = layout.findViewById<TextView>(R.id.textView)
|
||||
|
||||
// Fill question text using language manager
|
||||
questionTextView.text = question.question?.let {
|
||||
LanguageManager.getText(languageID, it)
|
||||
} ?: ""
|
||||
questionTextView.text = question.question?.let { LanguageManager.getText(languageID, it) } ?: ""
|
||||
|
||||
// --- Schriftgrößen prozentual zur Bildschirmhöhe setzen ---
|
||||
// Passe die Prozente bei Bedarf an:
|
||||
setTextSizePercentOfScreenHeight(titleTextView, 0.03f) // 5.5% der Bildschirmhöhe
|
||||
setTextSizePercentOfScreenHeight(questionTextView,0.03f) // 5.0% der Bildschirmhöhe
|
||||
setTextSizePercentOfScreenHeight(clientCodeField, 0.025f) // 3.5% der Bildschirmhöhe
|
||||
setTextSizePercentOfScreenHeight(coachCodeField, 0.025f) // anpassen nach Geschmack
|
||||
// ----------------------------------------------------------
|
||||
setTextSizePercentOfScreenHeight(titleTextView, 0.03f)
|
||||
setTextSizePercentOfScreenHeight(questionTextView,0.03f)
|
||||
setTextSizePercentOfScreenHeight(clientCodeField, 0.025f)
|
||||
setTextSizePercentOfScreenHeight(coachCodeField, 0.025f)
|
||||
|
||||
// Load last used client code if available
|
||||
val lastClientCode = GlobalValues.LAST_CLIENT_CODE
|
||||
if (!lastClientCode.isNullOrBlank()) {
|
||||
clientCodeField.setText(lastClientCode)
|
||||
// *** WICHTIG: Nur den ERFOLGREICH GELADENEN Code verwenden ***
|
||||
val loadedClientCode = GlobalValues.LOADED_CLIENT_CODE
|
||||
if (!loadedClientCode.isNullOrBlank()) {
|
||||
clientCodeField.setText(loadedClientCode)
|
||||
clientCodeField.isEnabled = false
|
||||
} else {
|
||||
clientCodeField.setText(answers["client_code"] as? String ?: "")
|
||||
// Nichts ist geladen → Feld bleibt leer und editierbar
|
||||
clientCodeField.setText("")
|
||||
clientCodeField.isEnabled = true
|
||||
}
|
||||
|
||||
// Load saved coach code
|
||||
coachCodeField.setText(answers["coach_code"] as? String ?: "")
|
||||
|
||||
// Set click listener for Next button
|
||||
layout.findViewById<Button>(R.id.Qnext).setOnClickListener {
|
||||
onNextClicked(clientCodeField, coachCodeField)
|
||||
}
|
||||
|
||||
// Set click listener for Previous button
|
||||
layout.findViewById<Button>(R.id.Qprev).setOnClickListener {
|
||||
onPreviousClicked(clientCodeField, coachCodeField)
|
||||
}
|
||||
}
|
||||
|
||||
// Deaktiviert AutoSize und setzt textSize in sp prozentual zur Bildschirmhöhe
|
||||
private fun setTextSizePercentOfScreenHeight(view: TextView, percentOfHeight: Float) {
|
||||
val dm = layout.resources.displayMetrics
|
||||
val sp = (dm.heightPixels * percentOfHeight) / dm.scaledDensity
|
||||
@ -77,8 +66,10 @@ class HandlerClientCoachCode(
|
||||
view.setTextSize(TypedValue.COMPLEX_UNIT_SP, sp)
|
||||
}
|
||||
|
||||
// Handle Next button click
|
||||
private fun onNextClicked(clientCodeField: EditText, coachCodeField: EditText) {
|
||||
// 1) Ohne vorher geladenen Client NICHT weiter
|
||||
val loadedClientCode = GlobalValues.LOADED_CLIENT_CODE
|
||||
|
||||
if (!validate()) {
|
||||
val message = LanguageManager.getText(languageID, "fill_both_fields")
|
||||
showToast(message)
|
||||
@ -92,21 +83,18 @@ class HandlerClientCoachCode(
|
||||
val dbPath = layout.context.getDatabasePath("questionnaire_database")
|
||||
val dbExistedBefore = dbPath.exists()
|
||||
|
||||
// Check if client code already exists asynchronously
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val existingClient = MyApp.database.clientDao().getClientByCode(clientCode)
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
// Wenn Feld editierbar war und Code bereits existiert → Hinweis
|
||||
if (existingClient != null && clientCodeField.isEnabled) {
|
||||
// Client code already exists and field was editable
|
||||
val message = LanguageManager.getText(languageID, "client_code_exists")
|
||||
showToast(message)
|
||||
} else {
|
||||
// Either no existing client or re-using previous code
|
||||
saveAnswers(clientCode, coachCode)
|
||||
goToNextQuestion()
|
||||
|
||||
// Lösche DB-Dateien nur, wenn sie vorher nicht existierten
|
||||
if (!dbExistedBefore) {
|
||||
MyApp.database.close()
|
||||
dbPath.delete()
|
||||
@ -118,7 +106,6 @@ class HandlerClientCoachCode(
|
||||
}
|
||||
}
|
||||
|
||||
// Handle Previous button click
|
||||
private fun onPreviousClicked(clientCodeField: EditText, coachCodeField: EditText) {
|
||||
val clientCode = clientCodeField.text.toString()
|
||||
val coachCode = coachCodeField.text.toString()
|
||||
@ -126,21 +113,19 @@ class HandlerClientCoachCode(
|
||||
goToPreviousQuestion()
|
||||
}
|
||||
|
||||
// Validate that both fields are filled
|
||||
override fun validate(): Boolean {
|
||||
val clientCode = layout.findViewById<EditText>(R.id.client_code).text
|
||||
val coachCode = layout.findViewById<EditText>(R.id.coach_code).text
|
||||
return clientCode.isNotBlank() && coachCode.isNotBlank()
|
||||
}
|
||||
|
||||
// Save answers to shared state and global value
|
||||
private fun saveAnswers(clientCode: String, coachCode: String) {
|
||||
// Optional: LAST_CLIENT_CODE kann gesetzt bleiben; maßgeblich ist LOADED_CLIENT_CODE
|
||||
GlobalValues.LAST_CLIENT_CODE = clientCode
|
||||
answers["client_code"] = clientCode
|
||||
answers["coach_code"] = coachCode
|
||||
}
|
||||
|
||||
// Required override but not used here
|
||||
override fun saveAnswer() {
|
||||
// Not used
|
||||
}
|
||||
|
||||
@ -48,7 +48,7 @@ class HandlerOpeningScreen(private val activity: MainActivity) {
|
||||
val pathExists = File(dbPath).exists()
|
||||
updateMainButtonsState(pathExists)
|
||||
|
||||
if (!editText.text.isNullOrBlank()) {
|
||||
if (pathExists && !editText.text.isNullOrBlank()) {
|
||||
buttonLoad.performClick()
|
||||
}
|
||||
}
|
||||
@ -154,21 +154,26 @@ class HandlerOpeningScreen(private val activity: MainActivity) {
|
||||
questionnaireFiles[button] = entry.file
|
||||
}
|
||||
updateButtonTexts()
|
||||
|
||||
val alwaysButtons = questionnaireEntries.mapIndexedNotNull { idx, entry ->
|
||||
val btn = dynamicButtons.getOrNull(idx)
|
||||
if (entry.condition is QuestionItem.Condition.AlwaysAvailable) btn else null
|
||||
}
|
||||
setButtonsEnabled(alwaysButtons)
|
||||
|
||||
dynamicButtons.forEach { button ->
|
||||
button.setOnClickListener {
|
||||
val clientCode = editText.text.toString().trim()
|
||||
GlobalValues.LAST_CLIENT_CODE = clientCode
|
||||
|
||||
// Optional: LAST_CLIENT_CODE synchronisieren (rein informativ)
|
||||
GlobalValues.LAST_CLIENT_CODE = GlobalValues.LOADED_CLIENT_CODE
|
||||
|
||||
startQuestionnaireForButton(button)
|
||||
setButtonsEnabled(dynamicButtons.filter { it == button })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun restorePreviousClientCode() {
|
||||
GlobalValues.LAST_CLIENT_CODE?.let { editText.setText(it) }
|
||||
}
|
||||
@ -276,10 +281,13 @@ class HandlerOpeningScreen(private val activity: MainActivity) {
|
||||
questionnaireFiles = questionnaireFiles,
|
||||
buttonPoints = buttonPoints,
|
||||
updateButtonTexts = { updateButtonTexts() },
|
||||
setButtonsEnabled = { setButtonsEnabled(it) }
|
||||
setButtonsEnabled = { setButtonsEnabled(it) },
|
||||
// Vor "Bearbeiten" ggf. den Load-Button ausführen
|
||||
triggerLoad = { buttonLoad.performClick() }
|
||||
).setup()
|
||||
}
|
||||
|
||||
|
||||
private fun setupUploadButton() {
|
||||
uploadButton.text = "Upload"
|
||||
uploadButton.setOnClickListener {
|
||||
|
||||
@ -42,10 +42,11 @@ class LoadButtonHandler(
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val client = MyApp.database.clientDao().getClientByCode(clientCode)
|
||||
if (client == null) {
|
||||
// Kein Profil → als NICHT geladen markieren
|
||||
GlobalValues.LOADED_CLIENT_CODE = null
|
||||
withContext(Dispatchers.Main) {
|
||||
val message = LanguageManager.getText(languageIDProvider(), "no_profile")
|
||||
Toast.makeText(activity, message, Toast.LENGTH_LONG).show()
|
||||
// enable only alwaysAvailable ones if no client found
|
||||
val questionnaireEntries = questionnaireEntriesProvider()
|
||||
val alwaysButtons = questionnaireEntries.mapIndexedNotNull { idx, entry ->
|
||||
val btn = dynamicButtonsProvider().getOrNull(idx)
|
||||
@ -56,27 +57,28 @@ class LoadButtonHandler(
|
||||
return@launch
|
||||
}
|
||||
|
||||
// Profil gefunden → als geladen markieren
|
||||
GlobalValues.LOADED_CLIENT_CODE = clientCode
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
updateMainButtonsState(true) // Datenbank vorhanden -> Buttons aktivieren
|
||||
updateMainButtonsState(true)
|
||||
}
|
||||
|
||||
handleNormalLoad(clientCode)
|
||||
}
|
||||
}
|
||||
|
||||
// Evaluierung der Bedingung: suspend, weil DB-Abfragen stattfinden.
|
||||
private suspend fun evaluateCondition(
|
||||
condition: QuestionItem.Condition?,
|
||||
clientCode: String,
|
||||
completedEntries: List<CompletedQuestionnaire>
|
||||
): Boolean {
|
||||
if (condition == null) return false
|
||||
|
||||
when (condition) {
|
||||
is QuestionItem.Condition.AlwaysAvailable -> return true
|
||||
return when (condition) {
|
||||
is QuestionItem.Condition.AlwaysAvailable -> true
|
||||
is QuestionItem.Condition.RequiresCompleted -> {
|
||||
val normalizedCompleted = completedEntries.map { normalizeQuestionnaireId(it.questionnaireId) }
|
||||
return condition.required.all { req ->
|
||||
condition.required.all { req ->
|
||||
val nReq = normalizeQuestionnaireId(req)
|
||||
normalizedCompleted.any { it.contains(nReq) || nReq.contains(it) }
|
||||
}
|
||||
@ -85,48 +87,37 @@ class LoadButtonHandler(
|
||||
val answers = MyApp.database.answerDao().getAnswersForClientAndQuestionnaire(clientCode, condition.questionnaire)
|
||||
val relevant = answers.find { it.questionId.endsWith(condition.questionId, ignoreCase = true) }
|
||||
val answerValue = relevant?.answerValue ?: ""
|
||||
return when (condition.operator) {
|
||||
when (condition.operator) {
|
||||
"==" -> answerValue == condition.value
|
||||
"!=" -> answerValue != condition.value
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
is QuestionItem.Condition.Combined -> {
|
||||
val reqOk = if (condition.requiresCompleted.isNullOrEmpty()) true
|
||||
else {
|
||||
val normalizedCompleted = completedEntries.map { normalizeQuestionnaireId(it.questionnaireId) }
|
||||
condition.requiresCompleted.all { req ->
|
||||
val nReq = normalizeQuestionnaireId(req)
|
||||
normalizedCompleted.any { it.contains(nReq) || nReq.contains(it) }
|
||||
}
|
||||
val normalizedCompleted = completedEntries.map { normalizeQuestionnaireId(it.questionnaireId) }
|
||||
val reqOk = condition.requiresCompleted.isNullOrEmpty() || condition.requiresCompleted.all { req ->
|
||||
val nReq = normalizeQuestionnaireId(req)
|
||||
normalizedCompleted.any { it.contains(nReq) || nReq.contains(it) }
|
||||
}
|
||||
if (!reqOk) return false
|
||||
val q = condition.questionCheck
|
||||
if (q != null) {
|
||||
val answers = MyApp.database.answerDao().getAnswersForClientAndQuestionnaire(clientCode, q.questionnaire)
|
||||
val relevant = answers.find { it.questionId.endsWith(q.questionId, ignoreCase = true) }
|
||||
val answerValue = relevant?.answerValue ?: ""
|
||||
return when (q.operator) {
|
||||
"==" -> answerValue == q.value
|
||||
"!=" -> answerValue != q.value
|
||||
else -> false
|
||||
}
|
||||
val q = condition.questionCheck ?: return true
|
||||
val answers = MyApp.database.answerDao().getAnswersForClientAndQuestionnaire(clientCode, q.questionnaire)
|
||||
val relevant = answers.find { it.questionId.endsWith(q.questionId, ignoreCase = true) }
|
||||
val answerValue = relevant?.answerValue ?: ""
|
||||
when (q.operator) {
|
||||
"==" -> answerValue == q.value
|
||||
"!=" -> answerValue != q.value
|
||||
else -> false
|
||||
}
|
||||
return reqOk
|
||||
}
|
||||
is QuestionItem.Condition.AnyOf -> {
|
||||
for (sub in condition.conditions) {
|
||||
val subRes = evaluateCondition(sub, clientCode, completedEntries)
|
||||
if (subRes) return true
|
||||
}
|
||||
return false
|
||||
condition.conditions.any { evaluateCondition(it, clientCode, completedEntries) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun normalizeQuestionnaireId(name: String): String {
|
||||
return name.lowercase().removeSuffix(".json")
|
||||
}
|
||||
private fun normalizeQuestionnaireId(name: String): String =
|
||||
name.lowercase().removeSuffix(".json")
|
||||
|
||||
private suspend fun handleNormalLoad(clientCode: String) {
|
||||
val completedEntries = withContext(Dispatchers.IO) {
|
||||
@ -147,7 +138,6 @@ class LoadButtonHandler(
|
||||
updateButtonTexts()
|
||||
}
|
||||
|
||||
// für jeden Fragebogen prüfen, ob er aktiv sein darf
|
||||
val enabledButtons = mutableListOf<Button>()
|
||||
val questionnaireEntries = questionnaireEntriesProvider()
|
||||
val dynamicButtons = dynamicButtonsProvider()
|
||||
@ -155,7 +145,6 @@ class LoadButtonHandler(
|
||||
for ((idx, entry) in questionnaireEntries.withIndex()) {
|
||||
val button = dynamicButtons.getOrNull(idx) ?: continue
|
||||
|
||||
// falls bereits erledigt: nicht anklickbar
|
||||
val isCompleted = completedEntries.any { completed ->
|
||||
normalizeQuestionnaireId(completed.questionnaireId).let { completedNorm ->
|
||||
val targetNorm = normalizeQuestionnaireId(entry.file)
|
||||
@ -164,7 +153,6 @@ class LoadButtonHandler(
|
||||
}
|
||||
if (isCompleted) continue
|
||||
|
||||
// auswerten der Bedingung (suspend)
|
||||
val condMet = evaluateCondition(entry.condition, clientCode, completedEntries)
|
||||
if (condMet) enabledButtons.add(button)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user