diff --git a/app/src/main/kotlin/edu/stanford/bdh/engagehf/bluetooth/component/AppScreenEvents.kt b/app/src/main/kotlin/edu/stanford/bdh/engagehf/bluetooth/component/AppScreenEvents.kt index 57a866a2e..06aabf5dd 100644 --- a/app/src/main/kotlin/edu/stanford/bdh/engagehf/bluetooth/component/AppScreenEvents.kt +++ b/app/src/main/kotlin/edu/stanford/bdh/engagehf/bluetooth/component/AppScreenEvents.kt @@ -33,5 +33,6 @@ class AppScreenEvents @Inject constructor( data object AddBloodPressureRecord : Event data object AddHeartRateRecord : Event data class NavigateToTab(val bottomBarItem: BottomBarItem) : Event + data object SymptomsDescriptionBottomSheet : Event } } diff --git a/app/src/main/kotlin/edu/stanford/bdh/engagehf/health/symptoms/SymptomsDescriptionBottomSheet.kt b/app/src/main/kotlin/edu/stanford/bdh/engagehf/health/symptoms/SymptomsDescriptionBottomSheet.kt new file mode 100644 index 000000000..5bd11285c --- /dev/null +++ b/app/src/main/kotlin/edu/stanford/bdh/engagehf/health/symptoms/SymptomsDescriptionBottomSheet.kt @@ -0,0 +1,89 @@ +package edu.stanford.bdh.engagehf.health.symptoms + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import edu.stanford.bdh.engagehf.R +import edu.stanford.spezi.core.design.component.VerticalSpacer +import edu.stanford.spezi.core.design.theme.Spacings +import edu.stanford.spezi.core.design.theme.SpeziTheme +import edu.stanford.spezi.core.design.theme.TextStyles +import edu.stanford.spezi.core.design.theme.ThemePreviews + +@Composable +fun SymptomsDescriptionBottomSheet() { + LazyColumn( + modifier = Modifier + .fillMaxWidth() + .padding(Spacings.medium), + horizontalAlignment = Alignment.CenterHorizontally + ) { + item { + Text( + text = stringResource(R.string.symptoms_description_title), + style = TextStyles.titleLarge + ) + VerticalSpacer() + TitleDescriptionItem( + title = stringResource(R.string.overall_score_title), + description = stringResource(R.string.overall_score_description) + ) + TitleDescriptionItem( + title = stringResource(R.string.physical_limits_score_title), + description = stringResource(R.string.physical_limits_score_description) + ) + TitleDescriptionItem( + title = stringResource(R.string.social_limits_score_title), + description = stringResource(R.string.social_limits_score_description) + ) + TitleDescriptionItem( + title = stringResource(R.string.quality_of_life_score_title), + description = stringResource(R.string.quality_of_life_score_description) + ) + TitleDescriptionItem( + title = stringResource(R.string.symptoms_frequency_score_title), + description = stringResource(R.string.specific_symptoms_score_description) + ) + TitleDescriptionItem( + title = stringResource(R.string.dizziness_score_title), + description = stringResource(R.string.dizziness_score_description) + ) + VerticalSpacer() + } + } +} + +@Composable +fun TitleDescriptionItem(title: String, description: String) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = Spacings.small), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = title, + style = TextStyles.titleMedium + ) + Text( + text = description, + style = TextStyles.bodyMedium, + textAlign = TextAlign.Center + ) + } +} + +@ThemePreviews +@Composable +fun SymptomsDescriptionBottomSheetPreview() { + SpeziTheme(isPreview = true) { + SymptomsDescriptionBottomSheet() + } +} diff --git a/app/src/main/kotlin/edu/stanford/bdh/engagehf/health/symptoms/SymptomsScreen.kt b/app/src/main/kotlin/edu/stanford/bdh/engagehf/health/symptoms/SymptomsScreen.kt index 69d3afb72..07764413e 100644 --- a/app/src/main/kotlin/edu/stanford/bdh/engagehf/health/symptoms/SymptomsScreen.kt +++ b/app/src/main/kotlin/edu/stanford/bdh/engagehf/health/symptoms/SymptomsScreen.kt @@ -1,6 +1,5 @@ package edu.stanford.bdh.engagehf.health.symptoms -import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -12,9 +11,9 @@ import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.itemsIndexed -import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowDropDown +import androidx.compose.material.icons.filled.Info import androidx.compose.material.icons.outlined.Check import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.DropdownMenu @@ -31,9 +30,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.shadow import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp @@ -71,7 +68,6 @@ import edu.stanford.bdh.engagehf.R import edu.stanford.bdh.engagehf.health.HealthTableItem import edu.stanford.spezi.core.design.component.CenteredBoxContent import edu.stanford.spezi.core.design.component.VerticalSpacer -import edu.stanford.spezi.core.design.theme.Colors.onPrimary import edu.stanford.spezi.core.design.theme.Colors.primary import edu.stanford.spezi.core.design.theme.Colors.secondary import edu.stanford.spezi.core.design.theme.Sizes @@ -163,14 +159,9 @@ private fun LazyListScope.listHeader( onClick = { onAction(SymptomsViewModel.Action.Info) } ) { Icon( - painter = painterResource(id = edu.stanford.spezi.core.design.R.drawable.ic_info), + imageVector = Icons.Filled.Info, contentDescription = stringResource(R.string.info_icon_content_description), - modifier = Modifier - .size(Sizes.Icon.medium) - .background(primary, shape = CircleShape) - .shadow(Spacings.small, CircleShape) - .padding(Spacings.small), - tint = onPrimary + tint = primary ) } } @@ -280,12 +271,12 @@ fun SymptomsChart( } @Composable -fun SymptomsDropdown(headerData: HeaderData, onAction: (SymptomsViewModel.Action) -> Unit) { +private fun SymptomsDropdown(headerData: HeaderData, onAction: (SymptomsViewModel.Action) -> Unit) { Box(modifier = Modifier.wrapContentSize(Alignment.TopStart)) { TextButton(onClick = { onAction(SymptomsViewModel.Action.ToggleSymptomTypeDropdown(true)) }) { - SymptomTypeText(headerData.selectedSymptomType) + SymptomTypeTitleText(headerData.selectedSymptomType) Icon(Icons.Default.ArrowDropDown, contentDescription = "ArrowDropDown") } DropdownMenu( @@ -297,7 +288,7 @@ fun SymptomsDropdown(headerData: HeaderData, onAction: (SymptomsViewModel.Action val isSelected = headerData.selectedSymptomType == symptomType DropdownMenuItem( text = { - SymptomTypeText(symptomType) + headerData.selectedSymptomTypeText }, onClick = { onAction(SymptomsViewModel.Action.ToggleSymptomTypeDropdown(false)) @@ -317,16 +308,16 @@ fun SymptomsDropdown(headerData: HeaderData, onAction: (SymptomsViewModel.Action } @Composable -fun SymptomTypeText(symptomType: SymptomType) { +private fun SymptomTypeTitleText(symptomType: SymptomType) { Text( text = when (symptomType) { - SymptomType.OVERALL -> stringResource(R.string.symptom_type_overall) - SymptomType.PHYSICAL_LIMITS -> stringResource(R.string.symptom_type_physical) - SymptomType.SOCIAL_LIMITS -> stringResource(R.string.symptom_type_social) - SymptomType.QUALITY_OF_LIFE -> stringResource(R.string.symptom_type_quality) - SymptomType.SYMPTOMS_FREQUENCY -> stringResource(R.string.symptom_type_specific) - SymptomType.DIZZINESS -> stringResource(R.string.symptom_type_dizziness) + SymptomType.OVERALL -> stringResource(R.string.overall_score_title) + SymptomType.PHYSICAL_LIMITS -> stringResource(R.string.physical_limits_score_title) + SymptomType.SOCIAL_LIMITS -> stringResource(R.string.social_limits_score_title) + SymptomType.QUALITY_OF_LIFE -> stringResource(R.string.quality_of_life_score_title) + SymptomType.SYMPTOMS_FREQUENCY -> stringResource(R.string.symptoms_frequency_score_title) + SymptomType.DIZZINESS -> stringResource(R.string.dizziness_score_title) } ) } diff --git a/app/src/main/kotlin/edu/stanford/bdh/engagehf/health/symptoms/SymptomsUiStateMapper.kt b/app/src/main/kotlin/edu/stanford/bdh/engagehf/health/symptoms/SymptomsUiStateMapper.kt index dc00def18..0b9763957 100644 --- a/app/src/main/kotlin/edu/stanford/bdh/engagehf/health/symptoms/SymptomsUiStateMapper.kt +++ b/app/src/main/kotlin/edu/stanford/bdh/engagehf/health/symptoms/SymptomsUiStateMapper.kt @@ -1,8 +1,10 @@ package edu.stanford.bdh.engagehf.health.symptoms +import edu.stanford.bdh.engagehf.R import edu.stanford.bdh.engagehf.health.AggregatedHealthData import edu.stanford.bdh.engagehf.health.NewestHealthData import edu.stanford.bdh.engagehf.health.TableEntryData +import edu.stanford.spezi.core.design.component.StringResource import edu.stanford.spezi.core.utils.LocaleProvider import edu.stanford.spezi.core.utils.extensions.roundToDecimalPlaces import java.time.ZoneId @@ -40,13 +42,25 @@ class SymptomsUiStateMapper @Inject constructor( formattedValue = newestHealthData.formattedValue, formattedDate = newestHealthData.formattedDate, selectedSymptomType = selectedSymptomType, - isSelectedSymptomTypeDropdownExpanded = false + isSelectedSymptomTypeDropdownExpanded = false, + selectedSymptomTypeText = getSelectedSymptomTypeText(selectedSymptomType), ), valueFormatter = ::valueFormatter ) ) } + private fun getSelectedSymptomTypeText(selectedSymptomType: SymptomType): StringResource { + return when (selectedSymptomType) { + SymptomType.OVERALL -> StringResource(R.string.symptom_type_overall) + SymptomType.PHYSICAL_LIMITS -> StringResource(R.string.symptom_type_physical) + SymptomType.SOCIAL_LIMITS -> StringResource(R.string.symptom_type_social) + SymptomType.QUALITY_OF_LIFE -> StringResource(R.string.symptom_type_quality) + SymptomType.SYMPTOMS_FREQUENCY -> StringResource(R.string.symptom_type_specific) + SymptomType.DIZZINESS -> StringResource(R.string.symptom_type_dizziness) + } + } + private fun valueFormatter(value: Double): String { val year = value.toInt() val dayOfYearFraction = value - year diff --git a/app/src/main/kotlin/edu/stanford/bdh/engagehf/health/symptoms/SymptomsViewModel.kt b/app/src/main/kotlin/edu/stanford/bdh/engagehf/health/symptoms/SymptomsViewModel.kt index ce0bc2f25..6447adb00 100644 --- a/app/src/main/kotlin/edu/stanford/bdh/engagehf/health/symptoms/SymptomsViewModel.kt +++ b/app/src/main/kotlin/edu/stanford/bdh/engagehf/health/symptoms/SymptomsViewModel.kt @@ -5,9 +5,11 @@ package edu.stanford.bdh.engagehf.health.symptoms import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel +import edu.stanford.bdh.engagehf.bluetooth.component.AppScreenEvents import edu.stanford.bdh.engagehf.health.AggregatedHealthData import edu.stanford.bdh.engagehf.health.HealthRepository import edu.stanford.bdh.engagehf.health.TableEntryData +import edu.stanford.spezi.core.design.component.StringResource import edu.stanford.spezi.core.logging.speziLogger import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow @@ -23,6 +25,7 @@ import javax.inject.Inject class SymptomsViewModel @Inject internal constructor( private val symptomsUiStateMapper: SymptomsUiStateMapper, private val healthRepository: HealthRepository, + private val appScreenEvents: AppScreenEvents, ) : ViewModel() { private val logger by speziLogger() @@ -56,7 +59,12 @@ class SymptomsViewModel @Inject internal constructor( fun onAction(action: Action) { when (action) { - Action.Info -> {} + is Action.Info -> { + appScreenEvents.emit( + AppScreenEvents.Event.SymptomsDescriptionBottomSheet + ) + } + is Action.SelectSymptomType -> { _uiState.update { (it as? SymptomsUiState.Success)?.let { success -> @@ -110,6 +118,7 @@ data class SymptomsUiData( ) data class HeaderData( + val selectedSymptomTypeText: StringResource, val formattedValue: String, val formattedDate: String, val selectedSymptomType: SymptomType, diff --git a/app/src/main/kotlin/edu/stanford/bdh/engagehf/navigation/screens/AppScreen.kt b/app/src/main/kotlin/edu/stanford/bdh/engagehf/navigation/screens/AppScreen.kt index cb0bb3d0a..f83ad84cb 100644 --- a/app/src/main/kotlin/edu/stanford/bdh/engagehf/navigation/screens/AppScreen.kt +++ b/app/src/main/kotlin/edu/stanford/bdh/engagehf/navigation/screens/AppScreen.kt @@ -39,6 +39,7 @@ import edu.stanford.bdh.engagehf.health.bloodpressure.bottomsheet.AddBloodPressu import edu.stanford.bdh.engagehf.health.bloodpressure.bottomsheet.BloodPressureDescriptionBottomSheet import edu.stanford.bdh.engagehf.health.heartrate.bottomsheet.AddHeartRateBottomSheet import edu.stanford.bdh.engagehf.health.heartrate.bottomsheet.HeartRateDescriptionBottomSheet +import edu.stanford.bdh.engagehf.health.symptoms.SymptomsDescriptionBottomSheet import edu.stanford.bdh.engagehf.health.weight.bottomsheet.AddWeightBottomSheet import edu.stanford.bdh.engagehf.health.weight.bottomsheet.WeightDescriptionBottomSheet import edu.stanford.bdh.engagehf.medication.ui.MedicationScreen @@ -209,6 +210,7 @@ private fun BottomSheetContent( BottomSheetContent.BLOOD_PRESSURE_DESCRIPTION_INFO -> BloodPressureDescriptionBottomSheet() BottomSheetContent.HEART_RATE_DESCRIPTION_INFO -> HeartRateDescriptionBottomSheet() BottomSheetContent.BLUETOOTH_DEVICE_PAIRING -> BLEDevicePairingBottomSheet() + BottomSheetContent.SYMPTOMS_DESCRIPTION_INFO -> SymptomsDescriptionBottomSheet() } } diff --git a/app/src/main/kotlin/edu/stanford/bdh/engagehf/navigation/screens/AppScreenViewModel.kt b/app/src/main/kotlin/edu/stanford/bdh/engagehf/navigation/screens/AppScreenViewModel.kt index 159bb2001..72c17ae4e 100644 --- a/app/src/main/kotlin/edu/stanford/bdh/engagehf/navigation/screens/AppScreenViewModel.kt +++ b/app/src/main/kotlin/edu/stanford/bdh/engagehf/navigation/screens/AppScreenViewModel.kt @@ -89,6 +89,8 @@ class AppScreenViewModel @Inject constructor( BottomSheetContent.BLOOD_PRESSURE_DESCRIPTION_INFO } + AppScreenEvents.Event.SymptomsDescriptionBottomSheet -> BottomSheetContent.SYMPTOMS_DESCRIPTION_INFO + AppScreenEvents.Event.CloseBottomSheet -> { null } @@ -187,6 +189,7 @@ enum class BottomSheetContent { ADD_WEIGHT_RECORD, ADD_BLOOD_PRESSURE_RECORD, ADD_HEART_RATE_RECORD, + SYMPTOMS_DESCRIPTION_INFO, BLUETOOTH_DEVICE_PAIRING, } diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 95666d167..f41a0ca6c 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -91,5 +91,20 @@ Deine Geräte Zuletzt gesehen am %1$s Abmeldung fehlgeschlagen. + Einladungscode + Onboarding Kontakt + Ihre Symptome verstehen + Gesamt Score + Dieser Wert zeigt, wie sich Ihre Herzinsuffizienz insgesamt auf Sie auswirkt. Sie können einen Wert zwischen 0 und 100 erreichen. Ein höherer Wert bedeutet, dass es Ihnen besser geht. Ein Wert über 80 wird oft als gut angesehen. Ein Ziel der Herzmedikamente ist es, diesen Wert im Laufe der Zeit zu verbessern oder zu verhindern, dass er sich verringert. + Physikalische Grenzen Score + Dieser Wert gibt an, wie sehr Ihr Herz Ihre Fähigkeit, sich zu betätigen, beeinträchtigt. Höhere Werte bedeuten, dass Sie weniger eingeschränkt sind, und ein Wert über 80 wird oft als gut angesehen. + Soziale Grenzen Score + Dieser Wert gibt an, wie Ihr Herz Ihre Fähigkeit zu sozialen Aktivitäten beeinflusst. Höhere Werte bedeuten, dass Sie mehr tun können, während niedrigere Werte bedeuten, dass Sie durch Ihr Herz stärker eingeschränkt sind. + Bewertung der Lebensqualität + Dieser Wert gibt an, wie zufrieden Sie mit Ihren Herzsymptomen sind. Höhere Werte bedeuten, dass Sie insgesamt zufriedener sind, während niedrigere Werte bedeuten, dass Sie weniger zufrieden mit Ihrer Situation sind. + Symptom Häufigkeit + Dieser Wert gibt die Häufigkeit an, mit der Sie herzbezogene Symptome verspüren. Höhere Werte bedeuten weniger häufige Symptome und niedrigere Werte bedeuten häufigere Symptome. + Schwindel Score + Es ist wichtig, Ihren Schwindel im Auge zu behalten, denn Schwindel kann eine Nebenwirkung Ihres Herzens oder Ihrer Herzmedikamente sein. diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ae6cc12fb..fdf154c3f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -26,7 +26,7 @@ Physical Social Quality - Specific + Symptoms Dizziness No medication recommendations Current Dose: @@ -108,4 +108,17 @@ Invitation Code Onboarding Contact + Understanding Your Symptoms + Overall Score + This score shows how your heart failure affects you overall. You can score 0 to 100. A higher score means you are doing better. Over 80 is often considered doing well. A goal of heart medicines is to improve this score over time or keep it from decreasing. + Physical Limits Score + This represents how your heart affects your ability to do activity. Higher scores mean you are less limited, and over 80 is often considered doing well. + Social Limits Score + This score represents how your heart affects your ability to do social activities. Higher scores mean you are able to do more, while lower scores mean you are more limited by your heart. + Quality of Life Score + This score represents how content you are with your heart symptoms. Higher scores mean you are overall more content, while lower scores mean you are less satisfied with how you are doing. + Symptom Frequency + This represents the frequency you are experiencing heart-related symptoms. Higher scores mean less frequent symptoms and lower scores mean more frequent symptoms. + Dizziness Score + Your dizziness is important to keep track of because dizziness can be a side effect of your heart or your heart medicines. diff --git a/app/src/test/kotlin/edu/stanford/bdh/engagehf/health/symptoms/SymptomsUiStateMapperTest.kt b/app/src/test/kotlin/edu/stanford/bdh/engagehf/health/symptoms/SymptomsUiStateMapperTest.kt index 941ac5424..b43e16521 100644 --- a/app/src/test/kotlin/edu/stanford/bdh/engagehf/health/symptoms/SymptomsUiStateMapperTest.kt +++ b/app/src/test/kotlin/edu/stanford/bdh/engagehf/health/symptoms/SymptomsUiStateMapperTest.kt @@ -1,6 +1,8 @@ package edu.stanford.bdh.engagehf.health.symptoms import com.google.common.truth.Truth.assertThat +import edu.stanford.bdh.engagehf.R +import edu.stanford.spezi.core.design.component.StringResource import edu.stanford.spezi.core.utils.LocaleProvider import io.mockk.every import io.mockk.mockk @@ -125,6 +127,61 @@ class SymptomsUiStateMapperTest { assertThat(successStateOverall.data.chartData[0].xValues.size).isEqualTo(0) } + @Test + fun `mapSymptomsUiState when different symptomTypes returns correct selectedSymptomTypeText`() { + // Given + val symptomScores = listOf( + createSymptomScore(), + ) + + // When + val resultOverall = + symptomsUiStateMapper.mapSymptomsUiState(SymptomType.OVERALL, symptomScores) + val resultPhysical = + symptomsUiStateMapper.mapSymptomsUiState(SymptomType.PHYSICAL_LIMITS, symptomScores) + val resultSocial = + symptomsUiStateMapper.mapSymptomsUiState(SymptomType.SOCIAL_LIMITS, symptomScores) + val resultQuality = + symptomsUiStateMapper.mapSymptomsUiState(SymptomType.QUALITY_OF_LIFE, symptomScores) + val resultSpecific = + symptomsUiStateMapper.mapSymptomsUiState(SymptomType.SYMPTOMS_FREQUENCY, symptomScores) + val resultDizziness = + symptomsUiStateMapper.mapSymptomsUiState(SymptomType.DIZZINESS, symptomScores) + + // Then + assertThat(resultOverall).isInstanceOf(SymptomsUiState.Success::class.java) + assertThat(resultPhysical).isInstanceOf(SymptomsUiState.Success::class.java) + assertThat(resultSocial).isInstanceOf(SymptomsUiState.Success::class.java) + assertThat(resultQuality).isInstanceOf(SymptomsUiState.Success::class.java) + assertThat(resultSpecific).isInstanceOf(SymptomsUiState.Success::class.java) + assertThat(resultDizziness).isInstanceOf(SymptomsUiState.Success::class.java) + val successStateOverall = resultOverall as SymptomsUiState.Success + val successStatePhysical = resultPhysical as SymptomsUiState.Success + val successStateSocial = resultSocial as SymptomsUiState.Success + val successStateQuality = resultQuality as SymptomsUiState.Success + val successStateSpecific = resultSpecific as SymptomsUiState.Success + val successStateDizziness = resultDizziness as SymptomsUiState.Success + assertThat(successStateOverall.data.headerData.selectedSymptomTypeText).isEqualTo( + StringResource(R.string.symptom_type_overall) + ) + assertThat(successStatePhysical.data.headerData.selectedSymptomTypeText).isEqualTo( + StringResource(R.string.symptom_type_physical) + ) + + assertThat(successStateSocial.data.headerData.selectedSymptomTypeText).isEqualTo( + StringResource(R.string.symptom_type_social) + ) + assertThat(successStateQuality.data.headerData.selectedSymptomTypeText).isEqualTo( + StringResource(R.string.symptom_type_quality) + ) + assertThat(successStateSpecific.data.headerData.selectedSymptomTypeText).isEqualTo( + StringResource(R.string.symptom_type_specific) + ) + assertThat(successStateDizziness.data.headerData.selectedSymptomTypeText).isEqualTo( + StringResource(R.string.symptom_type_dizziness) + ) + } + private fun createSymptomScore( year: Int = 2024, month: Int = 8, diff --git a/app/src/test/kotlin/edu/stanford/bdh/engagehf/health/symptoms/SymptomsViewModelTest.kt b/app/src/test/kotlin/edu/stanford/bdh/engagehf/health/symptoms/SymptomsViewModelTest.kt index 716c82e9e..df576d5d4 100644 --- a/app/src/test/kotlin/edu/stanford/bdh/engagehf/health/symptoms/SymptomsViewModelTest.kt +++ b/app/src/test/kotlin/edu/stanford/bdh/engagehf/health/symptoms/SymptomsViewModelTest.kt @@ -1,11 +1,15 @@ package edu.stanford.bdh.engagehf.health.symptoms import com.google.common.truth.Truth.assertThat +import edu.stanford.bdh.engagehf.R +import edu.stanford.bdh.engagehf.bluetooth.component.AppScreenEvents import edu.stanford.bdh.engagehf.health.HealthRepository +import edu.stanford.spezi.core.design.component.StringResource import edu.stanford.spezi.core.testing.CoroutineTestRule import io.mockk.coEvery import io.mockk.every import io.mockk.mockk +import io.mockk.verify import kotlinx.coroutines.flow.flowOf import org.junit.Before import org.junit.Rule @@ -21,6 +25,7 @@ class SymptomsViewModelTest { private val symptomsUiStateMapper: SymptomsUiStateMapper = mockk() private val symptomScores = getSymptomScores() private val successState = SymptomsUiState.Success(getSymptomsUiData()) + private val appScreenEvents: AppScreenEvents = mockk(relaxed = true) private lateinit var viewModel: SymptomsViewModel @@ -99,6 +104,18 @@ class SymptomsViewModelTest { assertThat(uiState).isEqualTo(newState) } + @Test + fun `it should handle SymptomsDescriptionBottomSheet correctly`() { + // given + createViewModel() + + // when + viewModel.onAction(SymptomsViewModel.Action.Info) + + // then + verify { appScreenEvents.emit(AppScreenEvents.Event.SymptomsDescriptionBottomSheet) } + } + private fun getSymptomScores() = listOf( SymptomScore( overallScore = 80.0, @@ -117,10 +134,15 @@ class SymptomsViewModelTest { formattedDate = "", formattedValue = "", selectedSymptomType = SymptomType.SYMPTOMS_FREQUENCY, + selectedSymptomTypeText = StringResource(R.string.symptom_type_overall), ) ) private fun createViewModel() { - viewModel = SymptomsViewModel(symptomsUiStateMapper, healthRepository) + viewModel = SymptomsViewModel( + symptomsUiStateMapper = symptomsUiStateMapper, + healthRepository = healthRepository, + appScreenEvents = appScreenEvents, + ) } } diff --git a/app/src/test/kotlin/edu/stanford/bdh/engagehf/navigation/screens/AppScreenViewModelTest.kt b/app/src/test/kotlin/edu/stanford/bdh/engagehf/navigation/screens/AppScreenViewModelTest.kt index 4f905e41a..9b2092c05 100644 --- a/app/src/test/kotlin/edu/stanford/bdh/engagehf/navigation/screens/AppScreenViewModelTest.kt +++ b/app/src/test/kotlin/edu/stanford/bdh/engagehf/navigation/screens/AppScreenViewModelTest.kt @@ -268,4 +268,18 @@ class AppScreenViewModelTest { val updatedUiState = viewModel.uiState.value assertThat(updatedUiState.bottomSheetContent).isEqualTo(BottomSheetContent.HEART_RATE_DESCRIPTION_INFO) } + + @Test + fun `given SymptomsDescriptionBottomSheet is received then uiState should be updated`() = + runTestUnconfined { + // Given + val event = AppScreenEvents.Event.SymptomsDescriptionBottomSheet + + // When + appScreenEventsFlow.emit(event) + + // Then + val updatedUiState = viewModel.uiState.value + assertThat(updatedUiState.bottomSheetContent).isEqualTo(BottomSheetContent.SYMPTOMS_DESCRIPTION_INFO) + } }