diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c4f8f2ffbf..1f952b9bc47 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Handle window insets when displaying app content in edge-to-edge - Enable edge-to-edge support on all versions of Android +- Handle nullable inputs when removing last chip in the `ChipInputAutoCompleteTextView` ## 2025.05.20 diff --git a/app/src/main/java/org/simple/clinic/cvdrisk/CVDRiskRange.kt b/app/src/main/java/org/simple/clinic/cvdrisk/CVDRiskRange.kt index f0056124622..debea07f26f 100644 --- a/app/src/main/java/org/simple/clinic/cvdrisk/CVDRiskRange.kt +++ b/app/src/main/java/org/simple/clinic/cvdrisk/CVDRiskRange.kt @@ -15,9 +15,12 @@ data class CVDRiskRange( val level: CVDRiskLevel get() = CVDRiskLevel.compute(this) - val canPrescribeStatin: Boolean + val canPrescribeNonLabBasedStatin: Boolean get() = max >= 10 + val canPrescribeLabBasedStatin: Boolean + get() = max >= 20 + class RoomTypeConverter { @TypeConverter diff --git a/app/src/main/java/org/simple/clinic/summary/PatientSummaryUpdate.kt b/app/src/main/java/org/simple/clinic/summary/PatientSummaryUpdate.kt index d08eebe9874..051f534e50c 100644 --- a/app/src/main/java/org/simple/clinic/summary/PatientSummaryUpdate.kt +++ b/app/src/main/java/org/simple/clinic/summary/PatientSummaryUpdate.kt @@ -35,7 +35,7 @@ class PatientSummaryUpdate( private val isLabBasedStatinNudgeEnabled: Boolean, private val minAgeForStatin: Int = 40, private val maxAgeForCVDRisk: Int = 74, - private val minReqMaxRiskRangeForLabBasedNudge: Int = 10, + private val minReqMaxRiskRangeForLabBasedNudge: Int = 20, ) : Update { override fun update( @@ -319,9 +319,9 @@ class PatientSummaryUpdate( val bmiReading = event.bmiReading val calculatedRiskRange = event.riskRange val canPrescribeStatin = if (isLabBasedStatinNudgeEnabled) { - checkIfLabBasedNudgeCanBeShown(event.medicalHistory, event.riskRange) + calculatedRiskRange?.canPrescribeLabBasedStatin ?: false } else { - calculatedRiskRange?.canPrescribeStatin ?: false + calculatedRiskRange?.canPrescribeNonLabBasedStatin ?: false } val canShowSmokingStatusDialog = canPrescribeStatin && @@ -353,14 +353,6 @@ class PatientSummaryUpdate( } } - private fun checkIfLabBasedNudgeCanBeShown( - medicalHistory: MedicalHistory, - riskRange: CVDRiskRange? - ): Boolean { - val maxRiskRange = riskRange?.max ?: 0 - return !(medicalHistory.diagnosedWithDiabetes != Yes && maxRiskRange < minReqMaxRiskRangeForLabBasedNudge) - } - private fun labBasedRiskRange(calculatedRiskRange: CVDRiskRange?): CVDRiskRange? { if (calculatedRiskRange == null) return null diff --git a/app/src/main/java/org/simple/clinic/summary/compose/StatinNudgeView.kt b/app/src/main/java/org/simple/clinic/summary/compose/StatinNudgeView.kt index cdf85ab291c..cc6747554d4 100644 --- a/app/src/main/java/org/simple/clinic/summary/compose/StatinNudgeView.kt +++ b/app/src/main/java/org/simple/clinic/summary/compose/StatinNudgeView.kt @@ -96,6 +96,7 @@ fun StatinNudge( Spacer(modifier = Modifier.height(16.dp)) DescriptionText( isLabBasedStatinNudgeEnabled = isLabBasedStatinNudgeEnabled, + isNonLabBasedStatinNudgeEnabled = isNonLabBasedStatinNudgeEnabled, statinInfo = statinInfo ) @@ -262,17 +263,22 @@ fun RiskProgressBar( fun DescriptionText( statinInfo: StatinInfo, isLabBasedStatinNudgeEnabled: Boolean, + isNonLabBasedStatinNudgeEnabled: Boolean, ) { val text = descriptionText( isLabBasedStatinNudgeEnabled = isLabBasedStatinNudgeEnabled, + isNonLabBasedStatinNudgeEnabled = isNonLabBasedStatinNudgeEnabled, statinInfo = statinInfo, ) val textColor = when { - statinInfo.cvdRisk == null || statinInfo.cvdRisk.level == CVDRiskLevel.HIGH || statinInfo.hasDiabetes - -> SimpleTheme.colors.material.error + statinInfo.hasDiabetes || statinInfo.hasCVD -> SimpleTheme.colors.material.error + isLabBasedStatinNudgeEnabled && (statinInfo.cvdRisk == null || statinInfo.cvdRisk.level == CVDRiskLevel.VERY_HIGH) -> SimpleTheme.colors.material.error + isNonLabBasedStatinNudgeEnabled && (statinInfo.cvdRisk == null || statinInfo.cvdRisk.level == CVDRiskLevel.HIGH) -> SimpleTheme.colors.material.error + isLabBasedStatinNudgeEnabled && (statinInfo.isSmoker == Answer.Unanswered || statinInfo.cholesterol == null) -> + SimpleTheme.colors.onSurface67 - statinInfo.isSmoker == Answer.Unanswered || statinInfo.bmiReading == null || statinInfo.cholesterol == null -> + isNonLabBasedStatinNudgeEnabled && (statinInfo.isSmoker == Answer.Unanswered || statinInfo.bmiReading == null) -> SimpleTheme.colors.onSurface67 else -> SimpleTheme.colors.material.error @@ -294,46 +300,67 @@ fun DescriptionText( @Composable @ReadOnlyComposable private fun descriptionText( + isNonLabBasedStatinNudgeEnabled: Boolean, isLabBasedStatinNudgeEnabled: Boolean, statinInfo: StatinInfo ): AnnotatedString { - val maxCvdRiskRange = statinInfo.cvdRisk?.max ?: 0 - return when { statinInfo.hasCVD -> stringResource(R.string.statin_alert_refer_to_doctor) - statinInfo.hasDiabetes && statinInfo.age >= MIN_AGE_FOR_STATIN && isLabBasedStatinNudgeEnabled.not() -> + statinInfo.hasDiabetes && statinInfo.age >= MIN_AGE_FOR_STATIN -> stringResource(R.string.statin_alert_refer_to_doctor_diabetic_40) - statinInfo.hasDiabetes && statinInfo.age >= MIN_AGE_FOR_STATIN && isLabBasedStatinNudgeEnabled && maxCvdRiskRange < LAB_BASED_MIN_REQ_MAX_RISK_RANGE -> - stringResource(R.string.statin_alert_refer_to_doctor_diabetic_40) + isLabBasedStatinNudgeEnabled -> labBasedDescriptionText(statinInfo) + isNonLabBasedStatinNudgeEnabled -> nonLabBasedDescriptionText(statinInfo) - statinInfo.cvdRisk == null || statinInfo.cvdRisk.level == CVDRiskLevel.HIGH -> - stringResource(R.string.statin_alert_refer_to_doctor) + else -> stringResource(R.string.statin_alert_refer_to_doctor) + }.toAnnotatedString() +} - statinInfo.hasDiabetes && isLabBasedStatinNudgeEnabled -> - stringResource(R.string.statin_alert_refer_to_doctor_diabetic) +@Composable +@ReadOnlyComposable +private fun labBasedDescriptionText( + statinInfo: StatinInfo +): String { + return when { - statinInfo.isSmoker == Answer.Unanswered && statinInfo.bmiReading == null && isLabBasedStatinNudgeEnabled.not() -> - stringResource(R.string.statin_alert_add_smoking_and_bmi_info) + statinInfo.cvdRisk == null || statinInfo.cvdRisk.level == CVDRiskLevel.VERY_HIGH -> + stringResource(R.string.statin_alert_refer_to_doctor) + + statinInfo.isSmoker == Answer.Unanswered && statinInfo.cholesterol == null -> + stringResource(R.string.statin_alert_add_smoking_and_cholesterol_info) - statinInfo.isSmoker == Answer.Unanswered && statinInfo.bmiReading != null && isLabBasedStatinNudgeEnabled.not() -> + statinInfo.isSmoker == Answer.Unanswered && statinInfo.cholesterol != null -> stringResource(R.string.statin_alert_add_smoking_info) - statinInfo.isSmoker != Answer.Unanswered && statinInfo.bmiReading == null && isLabBasedStatinNudgeEnabled.not() -> - stringResource(R.string.statin_alert_add_bmi_info) + statinInfo.isSmoker != Answer.Unanswered && statinInfo.cholesterol == null -> + stringResource(R.string.statin_alert_add_cholesterol_info) - statinInfo.isSmoker == Answer.Unanswered && statinInfo.cholesterol == null && isLabBasedStatinNudgeEnabled -> - stringResource(R.string.statin_alert_add_smoking_and_cholesterol_info) + else -> stringResource(R.string.statin_alert_refer_to_doctor) + } +} + +@Composable +@ReadOnlyComposable +private fun nonLabBasedDescriptionText( + statinInfo: StatinInfo +): String { + return when { - statinInfo.isSmoker == Answer.Unanswered && statinInfo.cholesterol != null && isLabBasedStatinNudgeEnabled -> + statinInfo.cvdRisk == null || statinInfo.cvdRisk.level == CVDRiskLevel.HIGH -> + stringResource(R.string.statin_alert_refer_to_doctor) + + statinInfo.isSmoker == Answer.Unanswered && statinInfo.bmiReading == null -> + stringResource(R.string.statin_alert_add_smoking_and_bmi_info) + + statinInfo.isSmoker == Answer.Unanswered && statinInfo.bmiReading != null -> stringResource(R.string.statin_alert_add_smoking_info) - statinInfo.isSmoker != Answer.Unanswered && statinInfo.cholesterol == null && isLabBasedStatinNudgeEnabled -> - stringResource(R.string.statin_alert_add_cholesterol_info) + statinInfo.isSmoker != Answer.Unanswered && statinInfo.bmiReading == null -> + stringResource(R.string.statin_alert_add_bmi_info) else -> stringResource(R.string.statin_alert_refer_to_doctor) - }.toAnnotatedString() + } } @Composable diff --git a/app/src/main/java/org/simple/clinic/widgets/ChipInputAutoCompleteTextView.kt b/app/src/main/java/org/simple/clinic/widgets/ChipInputAutoCompleteTextView.kt index 6bd4b797ef9..823c592ded9 100644 --- a/app/src/main/java/org/simple/clinic/widgets/ChipInputAutoCompleteTextView.kt +++ b/app/src/main/java/org/simple/clinic/widgets/ChipInputAutoCompleteTextView.kt @@ -164,7 +164,7 @@ class ChipInputAutoCompleteTextView( } private fun removeLastChip() { - val lastInput = inputs.last() + val lastInput = inputs.lastOrNull() ?: return val lastChip = rootView .children .filterIsInstance() diff --git a/app/src/main/res/values-si-rLK/strings.xml b/app/src/main/res/values-si-rLK/strings.xml index 926cada51f4..7cc4be1740d 100644 --- a/app/src/main/res/values-si-rLK/strings.xml +++ b/app/src/main/res/values-si-rLK/strings.xml @@ -926,7 +926,6 @@ අවදානමක් සහිත රෝගීන් <b>ස්ටැටින් ප්‍රතිකාර</b> සදහා වෛද්‍යවරයා වෙත යොමු කරන්න වයස අවුරුදු 40 ට වැඩි, දියවැඩියා රෝගියෙකු නම් ස්ටැටින් ඖෂධ සඳහා වෛද්‍යවරයා වෙත යොමු කරන්න - දියවැඩියා රෝගියෙකු නම් ස්ටැටින් ඖෂධ සඳහා වෛද්‍යවරයා වෙත යොමු කරන්න දුම් පානය BMI අගය කොලෙස්ටරෝල් අගය එකතු කරන්න diff --git a/app/src/main/res/values-ta-rLK/strings.xml b/app/src/main/res/values-ta-rLK/strings.xml index 3e5fde990b3..24a8feb801d 100644 --- a/app/src/main/res/values-ta-rLK/strings.xml +++ b/app/src/main/res/values-ta-rLK/strings.xml @@ -925,7 +925,6 @@ ஆபத்தில் உள்ள நோயாளி <b>ஸ்டேடின் மருந்துக்காக</b> மருத்துவரை அணுகவும் நீரிழிவு நோயாளி, 40 வயதுக்கு மேற்பட்டவர் எனின் ஸ்டேடின்(statin) மருந்துக்கு மருத்துவரை நாடவும் - நீரிழிவு நோயாளி எனின் ஸ்டேடின் மருந்துக்கு மருத்துவரைப் நாடவும் புகைத்தலைச் சேர்க்க உடற் திணிவுச் சுட்டியினை சேர்க்க கொலஸ்ட்ரோலின் அளவைக் கூட்டுக diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4bfbda20727..e84160e5c58 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1093,7 +1093,6 @@ The Simple app contains private health information of patients (“Data”).\n\n AT RISK PATIENT Refer to doctor for <b>statin medicine</b> Diabetic patient, age above 40. Refer to doctor for <b>statin medicine</b> - Diabetic patient. Refer to doctor for <b>statin medicine</b> Add smoking Add BMI Add cholesterol diff --git a/app/src/test/java/org/simple/clinic/summary/PatientSummaryUpdateTest.kt b/app/src/test/java/org/simple/clinic/summary/PatientSummaryUpdateTest.kt index 3858f91364e..5dc208361b1 100644 --- a/app/src/test/java/org/simple/clinic/summary/PatientSummaryUpdateTest.kt +++ b/app/src/test/java/org/simple/clinic/summary/PatientSummaryUpdateTest.kt @@ -2377,7 +2377,7 @@ class PatientSummaryUpdateTest { fun `when statin info is loaded, then update the state`() { val statinInfo = StatinInfo( canShowStatinNudge = true, - cvdRisk = CVDRiskRange(11, 11), + cvdRisk = CVDRiskRange(11, 27), isSmoker = Yes, bmiReading = BMIReading(165f, 60f), hasCVD = true, @@ -2397,7 +2397,7 @@ class PatientSummaryUpdateTest { isSmoking = Yes, cholesterol = null, ), - riskRange = CVDRiskRange(11, 11), + riskRange = CVDRiskRange(11, 27), bmiReading = BMIReading(165f, 60f), )) .then(assertThatNext( @@ -2445,45 +2445,6 @@ class PatientSummaryUpdateTest { )) } - @Test - fun `when statin info is loaded and lab-based statin is enabled and has diabetes, then statin can be prescribed`() { - val statinInfo = StatinInfo( - canShowStatinNudge = true, - cvdRisk = null, - isSmoker = Yes, - bmiReading = BMIReading(165f, 60f), - hasCVD = true, - hasDiabetes = true, - age = 55, - cholesterol = null, - ) - val updateSpec = UpdateSpec(PatientSummaryUpdate( - isPatientReassignmentFeatureEnabled = true, - isPatientStatinNudgeV1Enabled = true, - isNonLabBasedStatinNudgeEnabled = true, - isLabBasedStatinNudgeEnabled = true, - )) - - updateSpec - .given(defaultModel) - .whenEvent(StatinInfoLoaded( - age = 55, - medicalHistory = TestData.medicalHistory( - hasHadStroke = Yes, - hasHadHeartAttack = Yes, - hasDiabetes = Yes, - isSmoking = Yes, - cholesterol = null, - ), - riskRange = CVDRiskRange(9, 9), - bmiReading = BMIReading(165f, 60f), - )) - .then(assertThatNext( - hasModel(defaultModel.updateStatinInfo(statinInfo)), - hasNoEffects() - )) - } - @Test fun `when statin info is loaded and lab-based statin is enabled and has diabetes and max risk is less than 10, then statin cannot be prescribed`() { val statinInfo = StatinInfo( @@ -2527,7 +2488,7 @@ class PatientSummaryUpdateTest { fun `when statin info is loaded and risk is low-high, then update the state and show smoking status dialog`() { val statinInfo = StatinInfo( canShowStatinNudge = true, - cvdRisk = CVDRiskRange(4, 11), + cvdRisk = CVDRiskRange(4, 27), isSmoker = Unanswered, bmiReading = BMIReading(165f, 60f), hasCVD = true, @@ -2546,7 +2507,7 @@ class PatientSummaryUpdateTest { isSmoking = Unanswered, cholesterol = null, ), - riskRange = CVDRiskRange(4, 11), + riskRange = CVDRiskRange(4, 27), bmiReading = BMIReading(165f, 60f), )) .then(assertThatNext(