Skip to content

Commit

Permalink
In the catalog app, load the questionnaire JSON file from the local s…
Browse files Browse the repository at this point in the history
…torage of the phone. (google#2088)

* load questionnaire json from local device storage of phone.

* Remove dead code.

* spotless apply.

* Address review comments.

* Address review comments.

* Add missing file.

* Address review comments.

* Address review comments.

* Restore copyright year.

* Address review comments.

* Address review comments.

* Rename argument keys.

* Add missing util file.

* Address review comments.

* Address review comments.

---------

Co-authored-by: Santosh Pingle <[email protected]>
  • Loading branch information
santosh-pingle and Santosh Pingle authored Aug 22, 2023
1 parent f71dab6 commit 4c2da74
Show file tree
Hide file tree
Showing 12 changed files with 196 additions and 111 deletions.
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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() {
Expand Down Expand Up @@ -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
)
)
)
}
}
}
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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) {
Expand All @@ -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() {
Expand Down Expand Up @@ -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
)
)
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -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)
}
}
}
Expand All @@ -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)
Expand Down Expand Up @@ -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"
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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<String>(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<Application>().assets.open(filename).bufferedReader().use { it.readText() }
}
}
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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) {
Expand All @@ -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() {
Expand Down Expand Up @@ -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
)
)
)
}
}
}
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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<BottomNavigationView>(R.id.bottom_navigation_view).visibility = value
}
Expand All @@ -52,4 +89,22 @@ class MainActivity : AppCompatActivity(R.layout.activity_main) {
val bottomNavigationView = findViewById<BottomNavigationView>(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,
)
)
}
}
}
Loading

0 comments on commit 4c2da74

Please sign in to comment.