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

Include the corresponding questionnaireResponseItemComponents for nested items in the group. #2005

Merged
Merged
Show file tree
Hide file tree
Changes from 10 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
Expand Up @@ -134,13 +134,15 @@ internal class QuestionnaireViewModel(application: Application, state: SavedStat
questionnaireResponse =
parser.parseResource(application.contentResolver.openInputStream(uri))
as QuestionnaireResponse
addMissingResponseItems(questionnaire.item, questionnaireResponse.item)
checkQuestionnaireResponse(questionnaire, questionnaireResponse)
}
state.contains(QuestionnaireFragment.EXTRA_QUESTIONNAIRE_RESPONSE_JSON_STRING) -> {
val questionnaireResponseJson: String =
state[QuestionnaireFragment.EXTRA_QUESTIONNAIRE_RESPONSE_JSON_STRING]!!
questionnaireResponse =
parser.parseResource(questionnaireResponseJson) as QuestionnaireResponse
addMissingResponseItems()
checkQuestionnaireResponse(questionnaire, questionnaireResponse)
}
else -> {
Expand Down Expand Up @@ -346,6 +348,131 @@ internal class QuestionnaireViewModel(application: Application, state: SavedStat
private val answerExpressionMap =
mutableMapOf<String, List<Questionnaire.QuestionnaireItemAnswerOptionComponent>>()

/**
* Adds empty [QuestionnaireResponseItemComponent]s to `responseItems` so that each
* [QuestionnaireItemComponent] in `questionnaireItems` has at least one corresponding
* [QuestionnaireResponseItemComponent]. This is because user-provided [QuestionnaireResponse]
* might not contain answers to unanswered or disabled questions. Note : this only applies to
* [QuestionnaireItemComponent]s nested under a group.
*/
private fun addMissingResponseItems() {
val linkIdToResponseItemsMap =
mutableMapOf<String, MutableList<QuestionnaireResponseItemComponent>>()
associateLinkId(questionnaire.item, linkIdToResponseItemsMap)
santosh-pingle marked this conversation as resolved.
Show resolved Hide resolved

addResponseItemsToMap(questionnaire.item, questionnaireResponse.item, linkIdToResponseItemsMap)

val responseItems = mutableListOf<QuestionnaireResponseItemComponent>()
buildResponseItemList(linkIdToResponseItemsMap, questionnaire.item, responseItems)
questionnaireResponse.item = responseItems
}

/**
* Adds linkId of the item present in the list [questionnaireItems] as a key, and an empty list of
* type [QuestionnaireResponseItemComponent] as a value to the map [linkIdToResponseItemsMap].
*/
private fun associateLinkId(
santosh-pingle marked this conversation as resolved.
Show resolved Hide resolved
questionnaireItems: List<QuestionnaireItemComponent>,
linkIdToResponseItemsMap: MutableMap<String, MutableList<QuestionnaireResponseItemComponent>>
) {
questionnaireItems.forEach {
linkIdToResponseItemsMap[it.linkId] = mutableListOf()
associateLinkId(it.item, linkIdToResponseItemsMap)
}
}

/**
* Adds response item present in the list [responseItems] corresponding to the linkId present in
* [questionnaireItems] to the map [linkedToResponseItemsMap], and if response item is missing
* then adds empty response item.
*/
private fun addResponseItemsToMap(
questionnaireItems: List<QuestionnaireItemComponent>,
responseItems: MutableList<QuestionnaireResponseItemComponent>,
linkedToResponseItemsMap: MutableMap<String, MutableList<QuestionnaireResponseItemComponent>>,
) {
val questionnaireIterator = questionnaireItems.iterator()
while (questionnaireIterator.hasNext()) {
val questionnaireItem = questionnaireIterator.next()
val responseItemComponents = responseItems.filter { questionnaireItem.linkId == it.linkId }
if (responseItemComponents.isNotEmpty()) { // add existing response items to the map.
linkedToResponseItemsMap[questionnaireItem.linkId]!!.addAll(responseItemComponents)
} else { // add empty response items to the map
linkedToResponseItemsMap[questionnaireItem.linkId]!!.add(
questionnaireItem.createQuestionnaireResponseItem()
)
}
// Add missing response items for non-repeating groups
if (questionnaireItem.type == Questionnaire.QuestionnaireItemType.GROUP &&
!questionnaireItem.repeats
) {
addResponseItemsToMap(
questionnaireItem.item,
linkedToResponseItemsMap[questionnaireItem.linkId]!!.first().item,
linkedToResponseItemsMap
)
}
}
}

/**
* Adds response items present in the map [linkedToResponseItemsMap] to the list [responseItems].
* The added items to the list [responseItems] correspond to the linkId of the item present in the
* list [questionnaireItems]
*/
private fun buildResponseItemList(
linkedToResponseItemsMap: MutableMap<String, MutableList<QuestionnaireResponseItemComponent>>,
questionnaireItems: List<QuestionnaireItemComponent>,
responseItems: MutableList<QuestionnaireResponseItemComponent>,
) {
val questionnaireIterator = questionnaireItems.iterator()
while (questionnaireIterator.hasNext()) {
val questionnaireItem = questionnaireIterator.next()
val responseItemComponents = linkedToResponseItemsMap[questionnaireItem.linkId]!!
if (!responseItems.containsAll(responseItemComponents)
) { // checks if response items present in the list.
responseItems.addAll(responseItemComponents)
}
// Add missing response items for non-repeating groups
if (questionnaireItem.type == Questionnaire.QuestionnaireItemType.GROUP &&
!questionnaireItem.repeats
) {
buildResponseItemList(
linkedToResponseItemsMap,
questionnaireItem.item,
responseItemComponents.first().item,
)
}
}
}

// Index based approach, this function will be removed.
santosh-pingle marked this conversation as resolved.
Show resolved Hide resolved
private fun addMissingResponseItems(
questionnaireItems: List<QuestionnaireItemComponent>,
responseItems: MutableList<QuestionnaireResponseItemComponent>
) {
val questionnaireIterator = questionnaireItems.iterator()
var previousIndex = -1
var currentIndex = -1
while (questionnaireIterator.hasNext()) {
previousIndex = currentIndex
val questionnaireItem = questionnaireIterator.next()
currentIndex = responseItems.indexOfLast { it.linkId == questionnaireItem.linkId }
// add empty response item.
if (currentIndex == -1) {
currentIndex = previousIndex + 1
var responseItem = questionnaireItem.createQuestionnaireResponseItem()
responseItems.add(currentIndex, responseItem)
}
// Add missing response items for non-repeating groups
if (questionnaireItem.type == Questionnaire.QuestionnaireItemType.GROUP &&
!questionnaireItem.repeats
) {
addMissingResponseItems(questionnaireItem.item, responseItems[currentIndex].item)
}
}
}

/**
* Returns current [QuestionnaireResponse] captured by the UI which includes answers of enabled
* questions.
Expand Down
Loading