Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into master-release
Browse files Browse the repository at this point in the history
  • Loading branch information
ndegwamartin committed Oct 2, 2024
2 parents ffb393f + 8d3dbc8 commit fad0ede
Show file tree
Hide file tree
Showing 13 changed files with 197 additions and 78 deletions.
2 changes: 1 addition & 1 deletion buildSrc/src/main/kotlin/Releases.kt
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ object Releases {

object DataCapture : LibraryArtifact {
override val artifactId = "data-capture"
override val version = "1.1.0-preview14-SNAPSHOT"
override val version = "1.2.0"
override val name = "Android FHIR Structured Data Capture Library"
}

Expand Down
20 changes: 12 additions & 8 deletions codelabs/datacapture/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ of the `app/build.gradle.kts` file of your project:
dependencies {
// ...

implementation("com.google.android.fhir:data-capture:0.1.0-beta03")
implementation("androidx.fragment:fragment-ktx:1.4.1")
implementation("com.google.android.fhir:data-capture:1.0.0")
implementation("androidx.fragment:fragment-ktx:1.5.5")
}
```

Expand Down Expand Up @@ -173,6 +173,13 @@ if (savedInstanceState == null) {
add<QuestionnaireFragment>(R.id.fragment_container_view, args = questionnaireParams)
}
}
// Submit button callback
supportFragmentManager.setFragmentResultListener(
QuestionnaireFragment.SUBMIT_REQUEST_KEY,
this,
) { _, _ ->
submitQuestionnaire()
}
```

Learn more about
Expand Down Expand Up @@ -244,12 +251,9 @@ questionnaire is already set up for
Find the `submitQuestionnaire()` method and add the following code:

```kotlin
lifecycleScope.launch {
val questionnaire =
jsonParser.parseResource(questionnaireJsonString) as Questionnaire
val bundle = ResourceMapper.extract(questionnaire, questionnaireResponse)
Log.d("extraction result", jsonParser.encodeResourceToString(bundle))
}
val questionnaire = jsonParser.parseResource(questionnaireJsonString) as Questionnaire
val bundle = ResourceMapper.extract(questionnaire, questionnaireResponse)
Log.d("extraction result", jsonParser.encodeResourceToString(bundle))
```

`ResourceMapper.extract()` requires a HAPI FHIR Questionnaire, which you can
Expand Down
12 changes: 6 additions & 6 deletions codelabs/datacapture/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,15 @@ android {
}

dependencies {
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.3")
implementation("androidx.core:core-ktx:1.12.0")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("com.google.android.material:material:1.10.0")
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.2")
implementation("androidx.core:core-ktx:1.13.1")
implementation("androidx.appcompat:appcompat:1.7.0")
implementation("com.google.android.material:material:1.12.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")

testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
androidTestImplementation("androidx.test.ext:junit:1.2.1")
androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1")

// 3 Add dependencies for Structured Data Capture Library and Fragment KTX
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2022-2023 Google LLC
* Copyright 2022-2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -17,8 +17,6 @@
package com.google.codelab.sdclibrary

import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {
Expand All @@ -32,24 +30,12 @@ class MainActivity : AppCompatActivity() {
// 4.2 Replace with code from the codelab to add a questionnaire fragment.
}

private fun submitQuestionnaire() {
// 5 Replace with code from the codelab to get a questionnaire response.
private fun submitQuestionnaire() =
lifecycleScope.launch {
// 5 Replace with code from the codelab to get a questionnaire response.

// 6 Replace with code from the codelab to extract FHIR resources from QuestionnaireResponse.
}

override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.submit_menu, menu)
return super.onCreateOptionsMenu(menu)
}

override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == R.id.submit) {
submitQuestionnaire()
return true
// 6 Replace with code from the codelab to extract FHIR resources from QuestionnaireResponse.
}
return super.onOptionsItemSelected(item)
}

private fun getStringFromAssets(fileName: String): String {
return assets.open(fileName).bufferedReader().use { it.readText() }
Expand Down
32 changes: 17 additions & 15 deletions codelabs/engine/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ file of your project:
dependencies {
// ...
implementation("com.google.android.fhir:engine:0.1.0-beta05")
implementation("com.google.android.fhir:engine:1.0.0")
}
```
Expand Down Expand Up @@ -256,6 +256,8 @@ outlined below will guide you through the process.
override fun getConflictResolver() = AcceptLocalConflictResolver
override fun getFhirEngine() = FhirApplication.fhirEngine(applicationContext)
override fun getUploadStrategy() = UploadStrategy.AllChangesSquashedBundlePut
}
```
Expand All @@ -282,7 +284,7 @@ outlined below will guide you through the process.
```kotlin
when (syncJobStatus) {
is SyncJobStatus.Finished -> {
is CurrentSyncJobStatus.Succeeded -> {
Toast.makeText(requireContext(), "Sync Finished", Toast.LENGTH_SHORT).show()
viewModel.searchPatientsByName("")
}
Expand Down Expand Up @@ -434,20 +436,20 @@ the UI to update, incorporate the following conditional code block:
```kotlin
viewModelScope.launch {
val fhirEngine = FhirApplication.fhirEngine(getApplication())
if (nameQuery.isNotEmpty()) {
val searchResult = fhirEngine.search<Patient> {
filter(
Patient.NAME,
{
modifier = StringFilterModifier.CONTAINS
value = nameQuery
},
)
val fhirEngine = FhirApplication.fhirEngine(getApplication())
val searchResult = fhirEngine.search<Patient> {
if (nameQuery.isNotEmpty()) {
filter(
Patient.NAME,
{
modifier = StringFilterModifier.CONTAINS
value = nameQuery
},
)
}
}
liveSearchedPatients.value = searchResult.map { it.resource }
}
liveSearchedPatients.value = searchResult.map { it.resource }
}
}
```
Here, if the `nameQuery` is not empty, the search function will filter the
Expand Down
18 changes: 9 additions & 9 deletions codelabs/engine/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,18 @@ android {
}

dependencies {
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.3")
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.2")

implementation("androidx.core:core-ktx:1.12.0")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("com.google.android.material:material:1.10.0")
implementation("androidx.core:core-ktx:1.13.1")
implementation("androidx.appcompat:appcompat:1.7.0")
implementation("com.google.android.material:material:1.12.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
implementation("androidx.work:work-runtime-ktx:2.8.1")
implementation("androidx.work:work-runtime-ktx:2.9.1")

testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
androidTestImplementation("androidx.test.ext:junit:1.2.1")
androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1")

implementation("com.google.android.fhir:engine:0.1.0-beta05")
implementation("androidx.fragment:fragment-ktx:1.6.1")
implementation("com.google.android.fhir:engine:1.0.0")
implementation("androidx.fragment:fragment-ktx:1.8.3")
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2023-2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -35,7 +35,7 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.google.android.fhir.codelabs.engine.databinding.FragmentPatientListViewBinding
import com.google.android.fhir.sync.SyncJobStatus
import com.google.android.fhir.sync.CurrentSyncJobStatus
import kotlinx.coroutines.launch

class PatientListFragment : Fragment() {
Expand Down Expand Up @@ -75,7 +75,7 @@ class PatientListFragment : Fragment() {
}
}

private fun handleSyncJobStatus(syncJobStatus: SyncJobStatus) {
private fun handleSyncJobStatus(syncJobStatus: CurrentSyncJobStatus) {
// Add code to display Toast when sync job is complete
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2023-2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -23,16 +23,16 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.google.android.fhir.search.Order
import com.google.android.fhir.search.search
import com.google.android.fhir.sync.SyncJobStatus
import com.google.android.fhir.sync.CurrentSyncJobStatus
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.launch
import org.hl7.fhir.r4.model.Patient

class PatientListViewModel(application: Application) : AndroidViewModel(application) {
private val _pollState = MutableSharedFlow<SyncJobStatus>()
private val _pollState = MutableSharedFlow<CurrentSyncJobStatus>()

val pollState: Flow<SyncJobStatus>
val pollState: Flow<CurrentSyncJobStatus>
get() = _pollState

val liveSearchedPatients = MutableLiveData<List<Patient>>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,23 @@ class QuestionnaireFragment : Fragment() {
} else {
val errorViewModel: QuestionnaireValidationErrorViewModel by activityViewModels()
errorViewModel.setQuestionnaireAndValidation(viewModel.questionnaire, validationMap)
QuestionnaireValidationErrorMessageDialogFragment()
.show(
requireActivity().supportFragmentManager,
QuestionnaireValidationErrorMessageDialogFragment.TAG,
)
val validationErrorMessageDialog = QuestionnaireValidationErrorMessageDialogFragment()
if (requireArguments().containsKey(EXTRA_SHOW_SUBMIT_ANYWAY_BUTTON)) {
validationErrorMessageDialog.arguments =
Bundle().apply {
putBoolean(
EXTRA_SHOW_SUBMIT_ANYWAY_BUTTON,
requireArguments()
.getBoolean(
EXTRA_SHOW_SUBMIT_ANYWAY_BUTTON,
),
)
}
}
validationErrorMessageDialog.show(
requireActivity().supportFragmentManager,
QuestionnaireValidationErrorMessageDialogFragment.TAG,
)
}
}
}
Expand Down Expand Up @@ -407,6 +419,11 @@ class QuestionnaireFragment : Fragment() {
args.add(EXTRA_SHOW_NAVIGATION_IN_DEFAULT_LONG_SCROLL to value)
}

/** Setter to show/hide the Submit anyway button. This button is visible by default. */
fun setShowSubmitAnywayButton(value: Boolean) = apply {
args.add(EXTRA_SHOW_SUBMIT_ANYWAY_BUTTON to value)
}

@VisibleForTesting fun buildArgs() = bundleOf(*args.toTypedArray())

/** @return A [QuestionnaireFragment] with provided [Bundle] arguments. */
Expand Down Expand Up @@ -509,6 +526,12 @@ class QuestionnaireFragment : Fragment() {
internal const val EXTRA_SHOW_NAVIGATION_IN_DEFAULT_LONG_SCROLL =
"show-navigation-in-default-long-scroll"

/**
* A [Boolean] extra to show or hide the Submit anyway button in the questionnaire. Default is
* true.
*/
internal const val EXTRA_SHOW_SUBMIT_ANYWAY_BUTTON = "show-submit-anyway-button"

fun builder() = Builder()
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2023-2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -51,17 +51,23 @@ internal class QuestionnaireValidationErrorMessageDialogFragment(

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
isCancelable = false
return MaterialAlertDialogBuilder(requireContext())
.setView(onCreateCustomView())
.setPositiveButton(R.string.questionnaire_validation_error_fix_button_text) { dialog, _ ->
val currentDialog =
MaterialAlertDialogBuilder(requireContext()).setView(onCreateCustomView()).setPositiveButton(
R.string.questionnaire_validation_error_fix_button_text,
) { dialog, _ ->
setFragmentResult(RESULT_CALLBACK, bundleOf(RESULT_KEY to RESULT_VALUE_FIX))
dialog?.dismiss()
}
.setNegativeButton(R.string.questionnaire_validation_error_submit_button_text) { dialog, _ ->
if (arguments == null || requireArguments().getBoolean(EXTRA_SHOW_SUBMIT_ANYWAY_BUTTON, true)) {
currentDialog.setNegativeButton(R.string.questionnaire_validation_error_submit_button_text) {
dialog,
_,
->
setFragmentResult(RESULT_CALLBACK, bundleOf(RESULT_KEY to RESULT_VALUE_SUBMIT))
dialog?.dismiss()
}
.create()
}
return currentDialog.create()
}

@VisibleForTesting
Expand Down Expand Up @@ -97,6 +103,12 @@ internal class QuestionnaireValidationErrorMessageDialogFragment(
const val RESULT_KEY = "result"
const val RESULT_VALUE_FIX = "result_fix"
const val RESULT_VALUE_SUBMIT = "result_submit"

/**
* A [Boolean] extra to show or hide the Submit anyway button in the questionnaire. Default is
* true.
*/
internal const val EXTRA_SHOW_SUBMIT_ANYWAY_BUTTON = "show-submit-anyway-button"
}
}

Expand Down
Loading

0 comments on commit fad0ede

Please sign in to comment.