From 393ed25204b9cdca31bff774edefee44895467a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=E2=89=A1ZRS?= <12814349+LZRS@users.noreply.github.com> Date: Tue, 30 Sep 2025 11:39:34 +0300 Subject: [PATCH 1/5] Localize text forQuestionnaireValidationErrorMessageDialog --- .../QuestionnaireValidationErrorMessageDialogFragment.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireValidationErrorMessageDialogFragment.kt b/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireValidationErrorMessageDialogFragment.kt index 685da30678..81226fa2a8 100644 --- a/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireValidationErrorMessageDialogFragment.kt +++ b/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireValidationErrorMessageDialogFragment.kt @@ -18,6 +18,7 @@ package com.google.android.fhir.datacapture import android.app.Dialog import android.os.Bundle +import android.text.Spanned import android.view.LayoutInflater import android.view.View import android.widget.TextView @@ -32,6 +33,7 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import com.google.android.fhir.datacapture.extensions.flattened import com.google.android.fhir.datacapture.extensions.localizedFlyoverSpanned +import com.google.android.fhir.datacapture.extensions.localizedTextSpanned import com.google.android.fhir.datacapture.extensions.toSpanned import com.google.android.fhir.datacapture.validation.Invalid import com.google.android.fhir.datacapture.validation.ValidationResult @@ -129,14 +131,16 @@ internal class QuestionnaireValidationErrorViewModel : ViewModel() { } /** @return Texts associated with the failing [Questionnaire.QuestionnaireItemComponent]s. */ - fun getItemsTextWithValidationErrors(): List { + fun getItemsTextWithValidationErrors(): List { val invalidFields = validation?.filterValues { it.filterIsInstance().isNotEmpty() } ?: emptyMap() return questionnaire ?.item ?.flattened() ?.filter { invalidFields.contains(it.linkId) } - ?.map { if (it.text.isNullOrEmpty()) it.localizedFlyoverSpanned.toString() else it.text } + ?.mapNotNull { + if (it.text.isNullOrEmpty()) it.localizedFlyoverSpanned else it.localizedTextSpanned + } ?: emptyList() } } From 7f6795a1ed99d99c9e3cda2d35ca2c3c39f1dd64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=E2=89=A1ZRS?= <12814349+LZRS@users.noreply.github.com> Date: Thu, 9 Oct 2025 01:22:10 +0300 Subject: [PATCH 2/5] Add prefix as text that can be used to associate failing item --- .../QuestionnaireValidationErrorMessageDialogFragment.kt | 8 +++++++- .../extensions/MoreQuestionnaireItemComponents.kt | 4 +++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireValidationErrorMessageDialogFragment.kt b/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireValidationErrorMessageDialogFragment.kt index 81226fa2a8..db39b33dc7 100644 --- a/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireValidationErrorMessageDialogFragment.kt +++ b/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireValidationErrorMessageDialogFragment.kt @@ -33,7 +33,9 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import com.google.android.fhir.datacapture.extensions.flattened import com.google.android.fhir.datacapture.extensions.localizedFlyoverSpanned +import com.google.android.fhir.datacapture.extensions.localizedPrefixSpanned import com.google.android.fhir.datacapture.extensions.localizedTextSpanned +import com.google.android.fhir.datacapture.extensions.takeIfNotBlank import com.google.android.fhir.datacapture.extensions.toSpanned import com.google.android.fhir.datacapture.validation.Invalid import com.google.android.fhir.datacapture.validation.ValidationResult @@ -139,7 +141,11 @@ internal class QuestionnaireValidationErrorViewModel : ViewModel() { ?.flattened() ?.filter { invalidFields.contains(it.linkId) } ?.mapNotNull { - if (it.text.isNullOrEmpty()) it.localizedFlyoverSpanned else it.localizedTextSpanned + // Use the question text if available, otherwise fall back to the fly-over and then the + // prefix. + it.localizedTextSpanned?.takeIfNotBlank() + ?: it.localizedFlyoverSpanned?.takeIfNotBlank() + ?: it.localizedPrefixSpanned?.takeIfNotBlank() } ?: emptyList() } diff --git a/datacapture/src/main/java/com/google/android/fhir/datacapture/extensions/MoreQuestionnaireItemComponents.kt b/datacapture/src/main/java/com/google/android/fhir/datacapture/extensions/MoreQuestionnaireItemComponents.kt index a29e0151e8..8fe649f9f9 100644 --- a/datacapture/src/main/java/com/google/android/fhir/datacapture/extensions/MoreQuestionnaireItemComponents.kt +++ b/datacapture/src/main/java/com/google/android/fhir/datacapture/extensions/MoreQuestionnaireItemComponents.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 Google LLC + * Copyright 2023-2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -381,6 +381,8 @@ internal fun String.toSpanned(): Spanned { return HtmlCompat.fromHtml(this, HtmlCompat.FROM_HTML_MODE_COMPACT) } +internal fun Spanned.takeIfNotBlank(): Spanned? = takeIf { it.isNotBlank() } + /** * Localized and spanned value of [Questionnaire.QuestionnaireItemComponent.text] if translation is * present. Default value otherwise. From e6ddf1291ac1b5d0ba2e59ddb00e7dc2f4247f96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=E2=89=A1ZRS?= <12814349+LZRS@users.noreply.github.com> Date: Thu, 9 Oct 2025 01:26:02 +0300 Subject: [PATCH 3/5] Replace \n with
for html spannable text --- .../datacapture/extensions/MoreQuestionnaireItemComponents.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/datacapture/src/main/java/com/google/android/fhir/datacapture/extensions/MoreQuestionnaireItemComponents.kt b/datacapture/src/main/java/com/google/android/fhir/datacapture/extensions/MoreQuestionnaireItemComponents.kt index 8fe649f9f9..ade257b0f1 100644 --- a/datacapture/src/main/java/com/google/android/fhir/datacapture/extensions/MoreQuestionnaireItemComponents.kt +++ b/datacapture/src/main/java/com/google/android/fhir/datacapture/extensions/MoreQuestionnaireItemComponents.kt @@ -378,7 +378,7 @@ val QuestionnaireItemComponent.hasHelpButton: Boolean /** Converts Text with HTML Tag to formatted text. */ internal fun String.toSpanned(): Spanned { - return HtmlCompat.fromHtml(this, HtmlCompat.FROM_HTML_MODE_COMPACT) + return HtmlCompat.fromHtml(this.replace("\n", "
"), HtmlCompat.FROM_HTML_MODE_COMPACT) } internal fun Spanned.takeIfNotBlank(): Spanned? = takeIf { it.isNotBlank() } From 31e919b53a66ef6150bc4ac2cf84467fe1b0bedf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=E2=89=A1ZRS?= <12814349+LZRS@users.noreply.github.com> Date: Thu, 9 Oct 2025 12:52:38 +0300 Subject: [PATCH 4/5] Use takeIfNotBlank as a private function in QuestionnaireValidationErrorMessageDialogFragment --- .../QuestionnaireValidationErrorMessageDialogFragment.kt | 3 ++- .../datacapture/extensions/MoreQuestionnaireItemComponents.kt | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireValidationErrorMessageDialogFragment.kt b/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireValidationErrorMessageDialogFragment.kt index db39b33dc7..d4860615c2 100644 --- a/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireValidationErrorMessageDialogFragment.kt +++ b/datacapture/src/main/java/com/google/android/fhir/datacapture/QuestionnaireValidationErrorMessageDialogFragment.kt @@ -35,7 +35,6 @@ import com.google.android.fhir.datacapture.extensions.flattened import com.google.android.fhir.datacapture.extensions.localizedFlyoverSpanned import com.google.android.fhir.datacapture.extensions.localizedPrefixSpanned import com.google.android.fhir.datacapture.extensions.localizedTextSpanned -import com.google.android.fhir.datacapture.extensions.takeIfNotBlank import com.google.android.fhir.datacapture.extensions.toSpanned import com.google.android.fhir.datacapture.validation.Invalid import com.google.android.fhir.datacapture.validation.ValidationResult @@ -149,4 +148,6 @@ internal class QuestionnaireValidationErrorViewModel : ViewModel() { } ?: emptyList() } + + private fun Spanned.takeIfNotBlank(): Spanned? = takeIf { it.isNotBlank() } } diff --git a/datacapture/src/main/java/com/google/android/fhir/datacapture/extensions/MoreQuestionnaireItemComponents.kt b/datacapture/src/main/java/com/google/android/fhir/datacapture/extensions/MoreQuestionnaireItemComponents.kt index ade257b0f1..372b262df6 100644 --- a/datacapture/src/main/java/com/google/android/fhir/datacapture/extensions/MoreQuestionnaireItemComponents.kt +++ b/datacapture/src/main/java/com/google/android/fhir/datacapture/extensions/MoreQuestionnaireItemComponents.kt @@ -381,8 +381,6 @@ internal fun String.toSpanned(): Spanned { return HtmlCompat.fromHtml(this.replace("\n", "
"), HtmlCompat.FROM_HTML_MODE_COMPACT) } -internal fun Spanned.takeIfNotBlank(): Spanned? = takeIf { it.isNotBlank() } - /** * Localized and spanned value of [Questionnaire.QuestionnaireItemComponent.text] if translation is * present. Default value otherwise. From 3678ec3f019b2f14837119a3f5f228f098411542 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=E2=89=A1ZRS?= <12814349+LZRS@users.noreply.github.com> Date: Thu, 9 Oct 2025 16:18:49 +0300 Subject: [PATCH 5/5] Replace \n with "), HtmlCompat.FROM_HTML_MODE_COMPACT) + return HtmlCompat.fromHtml(this, HtmlCompat.FROM_HTML_MODE_COMPACT) } /**