Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HealthSummaryAction and MedicationsAction #86

Merged
merged 33 commits into from
Aug 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
d6beb58
renamed to AppScreenEvents
Basler182 Aug 15, 2024
5335d6a
added HealthSummaryRepository
Basler182 Aug 15, 2024
d4da4a6
added file provider and file paths
Basler182 Aug 15, 2024
6b288dd
finish rename tests
Basler182 Aug 15, 2024
46e712c
added firebase functions
Basler182 Aug 15, 2024
aab7120
added HealthSummaryService
Basler182 Aug 15, 2024
cd71635
fixed and expanded existing BluetoothViewModelTests
Basler182 Aug 15, 2024
8e4246f
added MedicationsAction and HealthSummaryAction
Basler182 Aug 15, 2024
59dce13
tested HealthSummaryRepository
Basler182 Aug 15, 2024
cf47148
added loading spinner while generating health summary
Basler182 Aug 15, 2024
0f30846
added account top app bar item
Basler182 Aug 16, 2024
56056f8
added actions to TopAppBar
Basler182 Aug 16, 2024
3610d39
adjusted AppScreenViewModelTests
Basler182 Aug 16, 2024
85b5ce3
renamed ShowDialog to ShowAccountDialog
Basler182 Aug 18, 2024
14bd101
renamed AppTopBar to AccountUiState
Basler182 Aug 18, 2024
68a8ee5
switched to typealias for generic map with wildcard types
Basler182 Aug 18, 2024
c4a5999
removed MaterialTheme import
Basler182 Aug 18, 2024
faa2104
added title to dialog
Basler182 Aug 18, 2024
5ff42d1
generateHealthSummary with ioDispatcher
Basler182 Aug 18, 2024
346ae96
use lambda for state changing
Basler182 Aug 18, 2024
3b5b0db
changed name and email to user info
Basler182 Aug 18, 2024
26801e9
improved catching of intent failures
Basler182 Aug 18, 2024
c7e3aab
removed unneeded isBottomSheetExpanded flag
Basler182 Aug 18, 2024
a837a54
removed bottom sheet expanded tests
Basler182 Aug 18, 2024
61f3fef
fixed VideoSectionDocumentToVideoSectionMapperTest
Basler182 Aug 18, 2024
cc0c2cc
fixed unit tests
Basler182 Aug 18, 2024
bff808e
adjusted domain model changes
Basler182 Aug 19, 2024
960ae30
tested UserSessionManager
Basler182 Aug 19, 2024
9a3c44b
tested AppScreenViewModel
Basler182 Aug 19, 2024
75de9ba
Merge branch 'main' into feature/issue-76-message-actions
Basler182 Aug 19, 2024
ff8168f
added deletion of health summary
Basler182 Aug 24, 2024
376eea5
Merge branch 'main' into feature/issue-76-message-actions
eldcn Aug 25, 2024
547525b
minor adjustments
eldcn Aug 25, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ android {

defaultConfig {
applicationId = "edu.stanford.bdh.engagehf"
versionCode = (project.findProperty("android.injected.version.code") as? String)?.toInt() ?: 1
versionCode =
(project.findProperty("android.injected.version.code") as? String)?.toInt() ?: 1
versionName = (project.findProperty("android.injected.version.name") as? String) ?: "1.0.0"
targetSdk = libs.versions.targetSdk.get().toInt()

Expand Down Expand Up @@ -49,6 +50,7 @@ dependencies {
implementation(project(":modules:onboarding"))

implementation(libs.firebase.firestore.ktx)
implementation(libs.firebase.functions.ktx)

implementation(libs.androidx.core.i18n)
implementation(libs.androidx.core.ktx)
Expand Down
9 changes: 9 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application>

</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,18 @@
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import edu.stanford.bdh.engagehf.bluetooth.component.BottomSheetEvents
import edu.stanford.bdh.engagehf.bluetooth.component.AppScreenEvents
import edu.stanford.bdh.engagehf.bluetooth.data.mapper.BluetoothUiStateMapper
import edu.stanford.bdh.engagehf.bluetooth.data.models.Action
import edu.stanford.bdh.engagehf.bluetooth.data.models.BluetoothUiState
import edu.stanford.bdh.engagehf.bluetooth.data.models.UiState
import edu.stanford.bdh.engagehf.bluetooth.measurements.MeasurementsRepository
import edu.stanford.bdh.engagehf.education.EngageEducationRepository
import edu.stanford.bdh.engagehf.messages.HealthSummaryService
import edu.stanford.bdh.engagehf.messages.MessageRepository
import edu.stanford.bdh.engagehf.messages.MessagesAction
import edu.stanford.bdh.engagehf.navigation.AppNavigationEvent
import edu.stanford.bdh.engagehf.navigation.screens.BottomBarItem
import edu.stanford.spezi.core.bluetooth.api.BLEService
import edu.stanford.spezi.core.bluetooth.data.model.BLEServiceEvent
import edu.stanford.spezi.core.bluetooth.data.model.BLEServiceState
Expand All @@ -34,9 +36,10 @@
private val uiStateMapper: BluetoothUiStateMapper,
private val measurementsRepository: MeasurementsRepository,
private val messageRepository: MessageRepository,
private val bottomSheetEvents: BottomSheetEvents,
private val appScreenEvents: AppScreenEvents,
private val navigator: Navigator,
private val engageEducationRepository: EngageEducationRepository,
private val healthSummaryService: HealthSummaryService,
) : ViewModel() {
private val logger by speziLogger()

Expand Down Expand Up @@ -94,7 +97,7 @@
}

is BLEServiceEvent.MeasurementReceived -> {
bottomSheetEvents.emit(BottomSheetEvents.Event.CloseBottomSheet)
appScreenEvents.emit(AppScreenEvents.Event.CloseBottomSheet)
_uiState.update {
it.copy(
measurementDialog = uiStateMapper.mapToMeasurementDialogUiState(
Expand Down Expand Up @@ -131,7 +134,11 @@
private fun observeMessages() {
viewModelScope.launch {
messageRepository.observeUserMessages().collect { messages ->
_uiState.update { it.copy(messages = messages) }
_uiState.update {
it.copy(
messages = messages
)
}
}
}
}
Expand All @@ -150,47 +157,45 @@

is Action.MessageItemClicked -> {
viewModelScope.launch {
val mappingResult = uiStateMapper.mapMessagesAction(action.message.action)
if (mappingResult.isSuccess) {
when (val mappedAction = mappingResult.getOrNull()!!) {
is MessagesAction.HealthSummaryAction -> { /* TODO */
}

is MessagesAction.MeasurementsAction -> {
bottomSheetEvents.emit(BottomSheetEvents.Event.DoNewMeasurement)
}
uiStateMapper.mapMessagesAction(action.message.action)
.onFailure { error ->
logger.e(error) { "Error while mapping action: ${action.message.action}" }
}
.onSuccess { mappedAction ->
val messageId = action.message.id
when (mappedAction) {
is MessagesAction.HealthSummaryAction -> {
handleHealthSummaryAction(messageId)
}

is MessagesAction.MedicationsAction -> { /* TODO */
}
is MessagesAction.MeasurementsAction -> {
appScreenEvents.emit(AppScreenEvents.Event.DoNewMeasurement)
}

is MessagesAction.QuestionnaireAction -> {
navigator.navigateTo(
AppNavigationEvent.QuestionnaireScreen(
mappedAction.questionnaireId
is MessagesAction.MedicationsAction -> {
appScreenEvents.emit(
AppScreenEvents.Event.NavigateToTab(
BottomBarItem.MEDICATION
)
)
)
}
}

is MessagesAction.VideoSectionAction -> {
viewModelScope.launch {
engageEducationRepository.getVideoBySectionAndVideoId(
mappedAction.videoSectionVideo.videoSectionId,
mappedAction.videoSectionVideo.videoId
).getOrNull()?.let { video ->
navigator.navigateTo(
EducationNavigationEvent.VideoSectionClicked(
video = video
)
is MessagesAction.QuestionnaireAction -> {
navigator.navigateTo(
AppNavigationEvent.QuestionnaireScreen(
mappedAction.questionnaireId
)
)
}

is MessagesAction.VideoSectionAction -> {
viewModelScope.launch {
handleVideoSectionAction(mappedAction)
}
}
}
messageRepository.completeMessage(messageId = messageId)
}
val messageId = action.message.id
messageRepository.completeMessage(messageId = messageId)
} else {
logger.e { "Error while mapping action: ${mappingResult.exceptionOrNull()}" }
}
}
}

Expand All @@ -200,6 +205,40 @@
}
}

private suspend fun handleVideoSectionAction(messageAction: MessagesAction.VideoSectionAction) {

Check warning on line 208 in app/src/main/kotlin/edu/stanford/bdh/engagehf/bluetooth/BluetoothViewModel.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/kotlin/edu/stanford/bdh/engagehf/bluetooth/BluetoothViewModel.kt#L208

Added line #L208 was not covered by tests
engageEducationRepository.getVideoBySectionAndVideoId(
messageAction.videoSectionVideo.videoSectionId,
messageAction.videoSectionVideo.videoId
).getOrNull()?.let { video ->
navigator.navigateTo(
EducationNavigationEvent.VideoSectionClicked(
video = video
)
)
}
}

private fun handleHealthSummaryAction(messageId: String) {
Basler182 marked this conversation as resolved.
Show resolved Hide resolved
val setLoading = { loading: Boolean ->
_uiState.update {
it.copy(
messages = it.messages.map { message ->
if (message.id == messageId) {
message.copy(isLoading = loading)

Check warning on line 227 in app/src/main/kotlin/edu/stanford/bdh/engagehf/bluetooth/BluetoothViewModel.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/kotlin/edu/stanford/bdh/engagehf/bluetooth/BluetoothViewModel.kt#L227

Added line #L227 was not covered by tests
} else {
message

Check warning on line 229 in app/src/main/kotlin/edu/stanford/bdh/engagehf/bluetooth/BluetoothViewModel.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/kotlin/edu/stanford/bdh/engagehf/bluetooth/BluetoothViewModel.kt#L229

Added line #L229 was not covered by tests
}
}
)
}
}
viewModelScope.launch {
setLoading(true)
healthSummaryService.generateHealthSummaryPdf()
setLoading(false)
}
}

public override fun onCleared() {
super.onCleared()
bleService.stop()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package edu.stanford.bdh.engagehf.bluetooth.component

import edu.stanford.bdh.engagehf.navigation.screens.BottomBarItem
import edu.stanford.spezi.core.coroutines.di.Dispatching
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableSharedFlow
Expand All @@ -10,7 +11,7 @@
import javax.inject.Singleton

@Singleton
class BottomSheetEvents @Inject constructor(
class AppScreenEvents @Inject constructor(

Check warning on line 14 in app/src/main/kotlin/edu/stanford/bdh/engagehf/bluetooth/component/AppScreenEvents.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/kotlin/edu/stanford/bdh/engagehf/bluetooth/component/AppScreenEvents.kt#L14

Added line #L14 was not covered by tests
@Dispatching.IO private val scope: CoroutineScope,
) {
private val _events = MutableSharedFlow<Event>(replay = 1)
Expand All @@ -30,5 +31,6 @@
data object AddWeightRecord : Event
data object AddBloodPressureRecord : Event
data object AddHeartRateRecord : Event
data class NavigateToTab(val bottomBarItem: BottomBarItem) : Event
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ package edu.stanford.bdh.engagehf.health

import androidx.lifecycle.ViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import edu.stanford.bdh.engagehf.bluetooth.component.BottomSheetEvents
import edu.stanford.bdh.engagehf.bluetooth.component.AppScreenEvents
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import javax.inject.Inject

@HiltViewModel
class HealthViewModel @Inject constructor(
private val bottomSheetEvents: BottomSheetEvents,
private val appScreenEvents: AppScreenEvents,
) : ViewModel() {
private val _uiState = MutableStateFlow(UiState())
val uiState = _uiState.asStateFlow()
Expand All @@ -19,12 +19,12 @@ class HealthViewModel @Inject constructor(
when (action) {
is Action.AddRecord -> {
val event = when (action.tab) {
HealthTab.Weight -> BottomSheetEvents.Event.AddWeightRecord
HealthTab.BloodPressure -> BottomSheetEvents.Event.AddBloodPressureRecord
HealthTab.HeartRate -> BottomSheetEvents.Event.AddHeartRateRecord
HealthTab.Weight -> AppScreenEvents.Event.AddWeightRecord
HealthTab.BloodPressure -> AppScreenEvents.Event.AddBloodPressureRecord
HealthTab.HeartRate -> AppScreenEvents.Event.AddHeartRateRecord
else -> return
}
bottomSheetEvents.emit(event)
appScreenEvents.emit(event)
}

is Action.UpdateTab -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import edu.stanford.bdh.engagehf.bluetooth.component.BottomSheetEvents
import edu.stanford.bdh.engagehf.bluetooth.component.AppScreenEvents
import edu.stanford.bdh.engagehf.health.HealthAction
import edu.stanford.bdh.engagehf.health.HealthRepository
import edu.stanford.bdh.engagehf.health.HealthUiState
Expand All @@ -19,7 +19,7 @@
class BloodPressureViewModel @Inject internal constructor(
private val uiStateMapper: HealthUiStateMapper,
private val healthRepository: HealthRepository,
private val bottomSheetEvents: BottomSheetEvents,
private val appScreenEvents: AppScreenEvents,

Check warning on line 22 in app/src/main/kotlin/edu/stanford/bdh/engagehf/health/bloodpressure/BloodPressureViewModel.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/kotlin/edu/stanford/bdh/engagehf/health/bloodpressure/BloodPressureViewModel.kt#L22

Added line #L22 was not covered by tests
) : ViewModel() {
private val _uiState = MutableStateFlow<HealthUiState>(HealthUiState.Loading)
val uiState = _uiState.asStateFlow()
Expand Down Expand Up @@ -56,7 +56,7 @@
}

HealthAction.DescriptionBottomSheet -> {
bottomSheetEvents.emit(BottomSheetEvents.Event.BloodPressureDescriptionBottomSheet)
appScreenEvents.emit(AppScreenEvents.Event.BloodPressureDescriptionBottomSheet)

Check warning on line 59 in app/src/main/kotlin/edu/stanford/bdh/engagehf/health/bloodpressure/BloodPressureViewModel.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/kotlin/edu/stanford/bdh/engagehf/health/bloodpressure/BloodPressureViewModel.kt#L59

Added line #L59 was not covered by tests
}

is HealthAction.ToggleTimeRangeDropdown -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import androidx.health.connect.client.units.Pressure
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import edu.stanford.bdh.engagehf.bluetooth.component.BottomSheetEvents
import edu.stanford.bdh.engagehf.bluetooth.component.AppScreenEvents
import edu.stanford.bdh.engagehf.health.HealthRepository
import edu.stanford.spezi.core.utils.MessageNotifier
import kotlinx.coroutines.flow.MutableStateFlow
Expand All @@ -19,7 +19,7 @@ import javax.inject.Inject

@HiltViewModel
internal class AddBloodPressureBottomSheetViewModel @Inject constructor(
private val bottomSheetEvents: BottomSheetEvents,
private val appScreenEvents: AppScreenEvents,
private val addBloodPressureBottomSheetUiStateMapper: AddBloodPressureBottomSheetUiStateMapper,
private val healthRepository: HealthRepository,
private val notifier: MessageNotifier,
Expand Down Expand Up @@ -62,7 +62,7 @@ internal class AddBloodPressureBottomSheetViewModel @Inject constructor(
}

Action.CloseSheet -> {
bottomSheetEvents.emit(BottomSheetEvents.Event.CloseBottomSheet)
appScreenEvents.emit(AppScreenEvents.Event.CloseBottomSheet)
}

Action.CloseUpdateDate -> {
Expand Down Expand Up @@ -112,7 +112,7 @@ internal class AddBloodPressureBottomSheetViewModel @Inject constructor(
healthRepository.saveRecord(bloodPressureRecord).onFailure {
notifier.notify("Failed to save blood pressure record")
}.onSuccess {
bottomSheetEvents.emit(BottomSheetEvents.Event.CloseBottomSheet)
appScreenEvents.emit(AppScreenEvents.Event.CloseBottomSheet)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import edu.stanford.bdh.engagehf.bluetooth.component.BottomSheetEvents
import edu.stanford.bdh.engagehf.bluetooth.component.AppScreenEvents
import edu.stanford.bdh.engagehf.health.HealthAction
import edu.stanford.bdh.engagehf.health.HealthRepository
import edu.stanford.bdh.engagehf.health.HealthUiState
Expand All @@ -20,7 +20,7 @@
class HeartRateViewModel @Inject internal constructor(
private val uiStateMapper: HealthUiStateMapper,
private val healthRepository: HealthRepository,
private val bottomSheetEvents: BottomSheetEvents,
private val appScreenEvents: AppScreenEvents,

Check warning on line 23 in app/src/main/kotlin/edu/stanford/bdh/engagehf/health/heartrate/HeartRateViewModel.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/kotlin/edu/stanford/bdh/engagehf/health/heartrate/HeartRateViewModel.kt#L23

Added line #L23 was not covered by tests
) : ViewModel() {
private val logger by speziLogger()

Expand Down Expand Up @@ -60,7 +60,7 @@
}

is HealthAction.DescriptionBottomSheet -> {
bottomSheetEvents.emit(BottomSheetEvents.Event.HeartRateDescriptionBottomSheet)
appScreenEvents.emit(AppScreenEvents.Event.HeartRateDescriptionBottomSheet)

Check warning on line 63 in app/src/main/kotlin/edu/stanford/bdh/engagehf/health/heartrate/HeartRateViewModel.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/kotlin/edu/stanford/bdh/engagehf/health/heartrate/HeartRateViewModel.kt#L63

Added line #L63 was not covered by tests
}

is HealthAction.ToggleTimeRangeDropdown -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import androidx.health.connect.client.records.HeartRateRecord
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import edu.stanford.bdh.engagehf.bluetooth.component.BottomSheetEvents
import edu.stanford.bdh.engagehf.bluetooth.component.AppScreenEvents
import edu.stanford.bdh.engagehf.health.HealthRepository
import edu.stanford.spezi.core.utils.MessageNotifier
import kotlinx.coroutines.flow.MutableStateFlow
Expand All @@ -18,7 +18,7 @@ import javax.inject.Inject

@HiltViewModel
internal class AddHeartRateBottomSheetViewModel @Inject constructor(
private val bottomSheetEvents: BottomSheetEvents,
private val appScreenEvents: AppScreenEvents,
private val healthRepository: HealthRepository,
private val addHeartRateBottomSheetUiStateMapper: AddHeartRateBottomSheetUiStateMapper,
private val notifier: MessageNotifier,
Expand All @@ -30,7 +30,7 @@ internal class AddHeartRateBottomSheetViewModel @Inject constructor(
fun onAction(action: Action) {
when (action) {
Action.CloseSheet -> {
bottomSheetEvents.emit(BottomSheetEvents.Event.CloseBottomSheet)
appScreenEvents.emit(AppScreenEvents.Event.CloseBottomSheet)
}

Action.SaveHeartRate -> {
Expand Down Expand Up @@ -83,7 +83,7 @@ internal class AddHeartRateBottomSheetViewModel @Inject constructor(
healthRepository.saveRecord(heartRate).onFailure {
notifier.notify("Failed to save heart rate record")
}.onSuccess {
bottomSheetEvents.emit(BottomSheetEvents.Event.CloseBottomSheet)
appScreenEvents.emit(AppScreenEvents.Event.CloseBottomSheet)
}
}
}
Expand Down
Loading
Loading