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

In the catalog app, load the questionnaire JSON file from the local storage of the phone. #2088

Merged
merged 23 commits into from
Aug 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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