diff --git a/catalog/src/main/java/com/google/android/fhir/catalog/BehaviorListFragment.kt b/catalog/src/main/java/com/google/android/fhir/catalog/BehaviorListFragment.kt
index bf1d6abe03..3706ad0f38 100644
--- a/catalog/src/main/java/com/google/android/fhir/catalog/BehaviorListFragment.kt
+++ b/catalog/src/main/java/com/google/android/fhir/catalog/BehaviorListFragment.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 Google LLC
+ * Copyright 2022-2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,15 +21,18 @@ import android.view.Gravity
import android.view.View
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
+import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
+import kotlinx.coroutines.launch
class BehaviorListFragment : Fragment(R.layout.behavior_list_fragment) {
private val viewModel: BehaviorListViewModel by viewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setUpBehaviorsRecyclerView()
+ (activity as? MainActivity)?.showOpenQuestionnaireMenu(true)
}
override fun onResume() {
@@ -63,14 +66,20 @@ class BehaviorListFragment : Fragment(R.layout.behavior_list_fragment) {
}
private fun launchQuestionnaireFragment(behavior: BehaviorListViewModel.Behavior) {
- findNavController()
- .navigate(
- BehaviorListFragmentDirections.actionBehaviorsFragmentToGalleryQuestionnaireFragment(
- context?.getString(behavior.textId) ?: "",
- behavior.questionnaireFileName,
- null,
- behavior.workFlow
+ viewLifecycleOwner.lifecycleScope.launch {
+ findNavController()
+ .navigate(
+ MainNavGraphDirections.actionGlobalGalleryQuestionnaireFragment(
+ questionnaireTitleKey = context?.getString(behavior.textId) ?: "",
+ questionnaireJsonStringKey =
+ getQuestionnaireJsonStringFromAssets(
+ context = requireContext(),
+ backgroundContext = coroutineContext,
+ fileName = behavior.questionnaireFileName,
+ ),
+ workflow = behavior.workFlow
+ )
)
- )
+ }
}
}
diff --git a/catalog/src/main/java/com/google/android/fhir/catalog/ComponentListFragment.kt b/catalog/src/main/java/com/google/android/fhir/catalog/ComponentListFragment.kt
index b85654c921..e562c23ed2 100644
--- a/catalog/src/main/java/com/google/android/fhir/catalog/ComponentListFragment.kt
+++ b/catalog/src/main/java/com/google/android/fhir/catalog/ComponentListFragment.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 Google LLC
+ * Copyright 2022-2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,9 +22,11 @@ import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
+import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
+import kotlinx.coroutines.launch
/** Fragment for the component list. */
class ComponentListFragment : Fragment(R.layout.component_list_fragment) {
@@ -33,6 +35,7 @@ class ComponentListFragment : Fragment(R.layout.component_list_fragment) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setUpComponentsRecyclerView()
+ (activity as? MainActivity)?.showOpenQuestionnaireMenu(true)
}
override fun onResume() {
@@ -84,14 +87,26 @@ class ComponentListFragment : Fragment(R.layout.component_list_fragment) {
}
private fun launchQuestionnaireFragment(component: ComponentListViewModel.Component) {
- findNavController()
- .navigate(
- ComponentListFragmentDirections.actionComponentsFragmentToGalleryQuestionnaireFragment(
- context?.getString(component.textId) ?: "",
- component.questionnaireFile,
- component.questionnaireFileWithValidation,
- component.workflow
+ viewLifecycleOwner.lifecycleScope.launch {
+ findNavController()
+ .navigate(
+ MainNavGraphDirections.actionGlobalGalleryQuestionnaireFragment(
+ questionnaireTitleKey = context?.getString(component.textId) ?: "",
+ questionnaireJsonStringKey =
+ getQuestionnaireJsonStringFromAssets(
+ context = requireContext(),
+ backgroundContext = coroutineContext,
+ fileName = component.questionnaireFile,
+ ),
+ questionnaireWithValidationJsonStringKey =
+ getQuestionnaireJsonStringFromAssets(
+ context = requireContext(),
+ backgroundContext = coroutineContext,
+ fileName = component.questionnaireFileWithValidation,
+ ),
+ workflow = component.workflow
+ )
)
- )
+ }
}
}
diff --git a/catalog/src/main/java/com/google/android/fhir/catalog/DemoQuestionnaireFragment.kt b/catalog/src/main/java/com/google/android/fhir/catalog/DemoQuestionnaireFragment.kt
index 103c94fcce..590506b669 100644
--- a/catalog/src/main/java/com/google/android/fhir/catalog/DemoQuestionnaireFragment.kt
+++ b/catalog/src/main/java/com/google/android/fhir/catalog/DemoQuestionnaireFragment.kt
@@ -85,10 +85,10 @@ class DemoQuestionnaireFragment : Fragment() {
childFragmentManager.setFragmentResultListener(SUBMIT_REQUEST_KEY, viewLifecycleOwner) { _, _ ->
onSubmitQuestionnaireClick()
}
- updateArguments()
if (savedInstanceState == null) {
addQuestionnaireFragment()
}
+ (activity as? MainActivity)?.showOpenQuestionnaireMenu(false)
}
override fun onResume() {
@@ -128,27 +128,16 @@ class DemoQuestionnaireFragment : Fragment() {
setHasOptionsMenu(true)
}
- private fun updateArguments() {
- requireArguments().putString(QUESTIONNAIRE_FILE_PATH_KEY, args.questionnaireFilePathKey)
- requireArguments()
- .putString(
- QUESTIONNAIRE_FILE_WITH_VALIDATION_PATH_KEY,
- args.questionnaireFileWithValidationPathKey
- )
- }
-
private fun addQuestionnaireFragment() {
viewLifecycleOwner.lifecycleScope.launch {
if (childFragmentManager.findFragmentByTag(QUESTIONNAIRE_FRAGMENT_TAG) == null) {
childFragmentManager.commit {
setReorderingAllowed(true)
- add(
- R.id.container,
+ val questionnaireFragment =
QuestionnaireFragment.builder()
- .setQuestionnaire(viewModel.getQuestionnaireJson())
- .build(),
- QUESTIONNAIRE_FRAGMENT_TAG
- )
+ .apply { setQuestionnaire(args.questionnaireJsonStringKey!!) }
+ .build()
+ add(R.id.container, questionnaireFragment, QUESTIONNAIRE_FRAGMENT_TAG)
}
}
}
@@ -161,15 +150,15 @@ class DemoQuestionnaireFragment : Fragment() {
*/
private fun replaceQuestionnaireFragmentWithQuestionnaireJson() {
// TODO: remove check once all files are added
- if (args.questionnaireFileWithValidationPathKey.isNullOrEmpty()) {
+ if (args.questionnaireWithValidationJsonStringKey.isNullOrEmpty()) {
return
}
viewLifecycleOwner.lifecycleScope.launch {
val questionnaireJsonString =
if (isErrorState) {
- viewModel.getQuestionnaireWithValidationJson()
+ args.questionnaireWithValidationJsonStringKey!!
} else {
- viewModel.getQuestionnaireJson()
+ args.questionnaireJsonStringKey!!
}
childFragmentManager.commit {
setReorderingAllowed(true)
@@ -225,9 +214,6 @@ class DemoQuestionnaireFragment : Fragment() {
companion object {
const val QUESTIONNAIRE_FRAGMENT_TAG = "questionnaire-fragment-tag"
- const val QUESTIONNAIRE_FILE_PATH_KEY = "questionnaire-file-path-key"
- const val QUESTIONNAIRE_FILE_WITH_VALIDATION_PATH_KEY =
- "questionnaire-file-with-validation-path-key"
}
}
diff --git a/catalog/src/main/java/com/google/android/fhir/catalog/DemoQuestionnaireViewModel.kt b/catalog/src/main/java/com/google/android/fhir/catalog/DemoQuestionnaireViewModel.kt
index dba615bbd0..264225325f 100644
--- a/catalog/src/main/java/com/google/android/fhir/catalog/DemoQuestionnaireViewModel.kt
+++ b/catalog/src/main/java/com/google/android/fhir/catalog/DemoQuestionnaireViewModel.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 Google LLC
+ * Copyright 2022-2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,55 +19,13 @@ package com.google.android.fhir.catalog
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.SavedStateHandle
-import androidx.lifecycle.viewModelScope
import ca.uhn.fhir.context.FhirContext
import ca.uhn.fhir.context.FhirVersionEnum
-import com.google.android.fhir.catalog.DemoQuestionnaireFragment.Companion.QUESTIONNAIRE_FILE_PATH_KEY
-import com.google.android.fhir.catalog.DemoQuestionnaireFragment.Companion.QUESTIONNAIRE_FILE_WITH_VALIDATION_PATH_KEY
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
import org.hl7.fhir.r4.model.QuestionnaireResponse
class DemoQuestionnaireViewModel(application: Application, private val state: SavedStateHandle) :
AndroidViewModel(application) {
- private val backgroundContext = viewModelScope.coroutineContext
- private var questionnaireJson: String? = null
- private var questionnaireWithValidationJson: String? = null
-
- init {
- viewModelScope.launch {
- getQuestionnaireJson()
- // TODO remove check once all files are added
- if (!state.get(QUESTIONNAIRE_FILE_WITH_VALIDATION_PATH_KEY).isNullOrEmpty()) {
- getQuestionnaireWithValidationJson()
- }
- }
- }
fun getQuestionnaireResponseJson(response: QuestionnaireResponse) =
FhirContext.forCached(FhirVersionEnum.R4).newJsonParser().encodeResourceToString(response)
-
- suspend fun getQuestionnaireJson(): String {
- return withContext(backgroundContext) {
- if (questionnaireJson == null) {
- questionnaireJson = readFileFromAssets(state[QUESTIONNAIRE_FILE_PATH_KEY]!!)
- }
- questionnaireJson!!
- }
- }
-
- suspend fun getQuestionnaireWithValidationJson(): String {
- return withContext(backgroundContext) {
- if (questionnaireWithValidationJson == null) {
- questionnaireWithValidationJson =
- readFileFromAssets(state[QUESTIONNAIRE_FILE_WITH_VALIDATION_PATH_KEY]!!)
- }
- questionnaireWithValidationJson!!
- }
- }
-
- private suspend fun readFileFromAssets(filename: String) =
- withContext(backgroundContext) {
- getApplication().assets.open(filename).bufferedReader().use { it.readText() }
- }
}
diff --git a/catalog/src/main/java/com/google/android/fhir/catalog/LayoutListFragment.kt b/catalog/src/main/java/com/google/android/fhir/catalog/LayoutListFragment.kt
index 0f0b37036b..080bc1fb16 100644
--- a/catalog/src/main/java/com/google/android/fhir/catalog/LayoutListFragment.kt
+++ b/catalog/src/main/java/com/google/android/fhir/catalog/LayoutListFragment.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 Google LLC
+ * Copyright 2022-2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,9 +21,11 @@ import android.view.Gravity
import android.view.View
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
+import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
+import kotlinx.coroutines.launch
/** Fragment for the layout list. */
class LayoutListFragment : Fragment(R.layout.layout_list_fragment) {
@@ -38,6 +40,7 @@ class LayoutListFragment : Fragment(R.layout.layout_list_fragment) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setUpLayoutsRecyclerView()
+ (activity as? MainActivity)?.showOpenQuestionnaireMenu(true)
}
private fun setUpLayoutsRecyclerView() {
@@ -67,14 +70,20 @@ class LayoutListFragment : Fragment(R.layout.layout_list_fragment) {
}
private fun launchQuestionnaireFragment(layout: LayoutListViewModel.Layout) {
- findNavController()
- .navigate(
- LayoutListFragmentDirections.actionLayoutsFragmentToGalleryQuestionnaireFragment(
- context?.getString(layout.textId) ?: "",
- layout.questionnaireFileName,
- null,
- layout.workflow
+ viewLifecycleOwner.lifecycleScope.launch {
+ findNavController()
+ .navigate(
+ MainNavGraphDirections.actionGlobalGalleryQuestionnaireFragment(
+ questionnaireTitleKey = context?.getString(layout.textId) ?: "",
+ questionnaireJsonStringKey =
+ getQuestionnaireJsonStringFromAssets(
+ context = requireContext(),
+ backgroundContext = coroutineContext,
+ fileName = layout.questionnaireFileName
+ ),
+ workflow = layout.workflow
+ )
)
- )
+ }
}
}
diff --git a/catalog/src/main/java/com/google/android/fhir/catalog/MainActivity.kt b/catalog/src/main/java/com/google/android/fhir/catalog/MainActivity.kt
index 5461689c44..4093da4026 100644
--- a/catalog/src/main/java/com/google/android/fhir/catalog/MainActivity.kt
+++ b/catalog/src/main/java/com/google/android/fhir/catalog/MainActivity.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 Google LLC
+ * Copyright 2021-2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,21 +16,58 @@
package com.google.android.fhir.catalog
+import android.net.Uri
import android.os.Bundle
+import android.view.Menu
+import android.view.MenuItem
import android.widget.TextView
+import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
+import androidx.lifecycle.lifecycleScope
import androidx.navigation.Navigation
+import androidx.navigation.findNavController
import androidx.navigation.ui.NavigationUI
import com.google.android.material.bottomnavigation.BottomNavigationView
+import kotlinx.coroutines.launch
class MainActivity : AppCompatActivity(R.layout.activity_main) {
+ private var showOpenQuestionnaireMenu = true
+ val getContentLauncher =
+ registerForActivityResult(ActivityResultContracts.GetContent()) {
+ it?.let { launchQuestionnaireFragment(it) }
+ }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setSupportActionBar(findViewById(R.id.toolbar))
setUpBottomNavigationView()
}
+ override fun onCreateOptionsMenu(menu: Menu): Boolean {
+ menuInflater.inflate(R.menu.open_questionnaire_menu, menu)
+ return true
+ }
+
+ override fun onPrepareOptionsMenu(menu: Menu): Boolean {
+ menu.findItem(R.id.select_questionnaire_menu).isVisible = showOpenQuestionnaireMenu
+ return true
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ return when (item.itemId) {
+ R.id.select_questionnaire_menu -> {
+ getContentLauncher.launch("application/json")
+ true
+ }
+ else -> super.onOptionsItemSelected(item)
+ }
+ }
+
+ fun showOpenQuestionnaireMenu(showMenu: Boolean) {
+ showOpenQuestionnaireMenu = showMenu
+ invalidateOptionsMenu()
+ }
+
fun showBottomNavigationView(value: Int) {
findViewById(R.id.bottom_navigation_view).visibility = value
}
@@ -52,4 +89,22 @@ class MainActivity : AppCompatActivity(R.layout.activity_main) {
val bottomNavigationView = findViewById(R.id.bottom_navigation_view)
NavigationUI.setupWithNavController(bottomNavigationView, navController)
}
+
+ private fun launchQuestionnaireFragment(uri: Uri) {
+ lifecycleScope.launch {
+ findNavController(R.id.nav_host_fragment)
+ .navigate(
+ MainNavGraphDirections.actionGlobalGalleryQuestionnaireFragment(
+ questionnaireTitleKey = "",
+ questionnaireJsonStringKey =
+ getQuestionnaireJsonStringFromFileUri(
+ context = applicationContext,
+ backgroundContext = coroutineContext,
+ uri = uri
+ ),
+ workflow = WorkflowType.DEFAULT,
+ )
+ )
+ }
+ }
}
diff --git a/catalog/src/main/java/com/google/android/fhir/catalog/ModalBottomSheetFragment.kt b/catalog/src/main/java/com/google/android/fhir/catalog/ModalBottomSheetFragment.kt
index 0626571962..004b0dd362 100644
--- a/catalog/src/main/java/com/google/android/fhir/catalog/ModalBottomSheetFragment.kt
+++ b/catalog/src/main/java/com/google/android/fhir/catalog/ModalBottomSheetFragment.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 Google LLC
+ * Copyright 2021-2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -60,6 +60,7 @@ class ModalBottomSheetFragment : BottomSheetDialogFragment() {
)
NavHostFragment.findNavController(this).navigateUp()
}
+ (activity as? MainActivity)?.showOpenQuestionnaireMenu(false)
}
companion object {
diff --git a/catalog/src/main/java/com/google/android/fhir/catalog/QuestionnaireFileOperationUtil.kt b/catalog/src/main/java/com/google/android/fhir/catalog/QuestionnaireFileOperationUtil.kt
new file mode 100644
index 0000000000..d5958593a4
--- /dev/null
+++ b/catalog/src/main/java/com/google/android/fhir/catalog/QuestionnaireFileOperationUtil.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.fhir.catalog
+
+import android.content.Context
+import android.net.Uri
+import java.io.BufferedReader
+import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.withContext
+
+suspend fun getQuestionnaireJsonStringFromAssets(
+ context: Context,
+ backgroundContext: CoroutineContext,
+ fileName: String
+): String {
+ return withContext(backgroundContext) {
+ context.assets.open(fileName).bufferedReader().use { it.readText() }
+ }
+}
+
+suspend fun getQuestionnaireJsonStringFromFileUri(
+ context: Context,
+ backgroundContext: CoroutineContext,
+ uri: Uri
+): String {
+ return withContext(backgroundContext) {
+ val reader = BufferedReader(context.contentResolver.openInputStream(uri)?.reader())
+ reader.use { reader -> reader.readText() }
+ }
+}
diff --git a/catalog/src/main/java/com/google/android/fhir/catalog/QuestionnaireResponseFragment.kt b/catalog/src/main/java/com/google/android/fhir/catalog/QuestionnaireResponseFragment.kt
index 025c485824..cbb06ff427 100644
--- a/catalog/src/main/java/com/google/android/fhir/catalog/QuestionnaireResponseFragment.kt
+++ b/catalog/src/main/java/com/google/android/fhir/catalog/QuestionnaireResponseFragment.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 Google LLC
+ * Copyright 2021-2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -46,6 +46,7 @@ class QuestionnaireResponseFragment : Fragment() {
setCloseOnClickListener()
view.findViewById(R.id.questionnaire_response_tv).text =
JSONObject(args.questionnaireResponse).toString(2)
+ (activity as? MainActivity)?.showOpenQuestionnaireMenu(false)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
diff --git a/catalog/src/main/res/menu/open_questionnaire_menu.xml b/catalog/src/main/res/menu/open_questionnaire_menu.xml
new file mode 100644
index 0000000000..6550c86ccf
--- /dev/null
+++ b/catalog/src/main/res/menu/open_questionnaire_menu.xml
@@ -0,0 +1,10 @@
+
diff --git a/catalog/src/main/res/navigation/nav_graph.xml b/catalog/src/main/res/navigation/nav_graph.xml
index 8428f73225..e9c457908e 100644
--- a/catalog/src/main/res/navigation/nav_graph.xml
+++ b/catalog/src/main/res/navigation/nav_graph.xml
@@ -35,10 +35,6 @@
android:id="@+id/action_componentsFragment_to_behaviorsFragment"
app:destination="@id/behaviorListFragment"
/>
-
-
-
-
-
+
-
+
Error
Widgets
Miscellaneous components
+ Open questionnaire