From 17e704ea650e64342e550ca9b6ea2e97b1d8fc4b Mon Sep 17 00:00:00 2001 From: santosh-pingle <86107848+santosh-pingle@users.noreply.github.com> Date: Mon, 5 Dec 2022 02:19:32 +0530 Subject: [PATCH] Help button workflow (#1697) * help button workflow in catalog app. * differentiate widgets and misc components header section. * Move component help icon to catalog res folder. * add new line to end of the file of questionnaire json * Address review comments. Co-authored-by: Santosh Pingle Co-authored-by: Omar Ismail <44980219+omarismail94@users.noreply.github.com> Co-authored-by: Jing Tang --- catalog/src/main/assets/component_help.json | 79 +++++++++++++++++++ .../fhir/catalog/ComponentListFragment.kt | 24 ++++-- .../fhir/catalog/ComponentListViewModel.kt | 31 +++++++- .../catalog/ComponentsRecyclerViewadapter.kt | 76 +++++++++++++----- catalog/src/main/res/drawable/ic_help.xml | 13 +++ .../res/layout/component_header_layout.xml | 18 +++++ catalog/src/main/res/values/dimens.xml | 2 + catalog/src/main/res/values/strings.xml | 5 +- 8 files changed, 220 insertions(+), 28 deletions(-) create mode 100644 catalog/src/main/assets/component_help.json create mode 100644 catalog/src/main/res/drawable/ic_help.xml create mode 100644 catalog/src/main/res/layout/component_header_layout.xml diff --git a/catalog/src/main/assets/component_help.json b/catalog/src/main/assets/component_help.json new file mode 100644 index 0000000000..5ed0fde3e4 --- /dev/null +++ b/catalog/src/main/assets/component_help.json @@ -0,0 +1,79 @@ +{ + "resourceType": "Questionnaire", + "item": [ + { + "linkId": "1", + "text": "Question title", + "type": "choice", + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button", + "display": "Radio Button" + } + ] + } + } + ], + "answerOption": [ + { + "valueCoding": { + "display": "Yes" + } + }, + { + "valueCoding": { + "display": "No" + } + }, + { + "valueCoding": { + "display": "Unknown" + } + } + ], + "item": [ + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-displayCategory", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-display-category", + "code": "instructions" + } + ] + } + } + ], + "linkId": "1.3", + "text": "Select one", + "type": "display" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "help" + } + ] + } + } + ], + "linkId": "1.3", + "text": "Only one answer can be selected. If none apply, skip the question.", + "type": "display" + } + ] + } + ] +} 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 4ae91d7817..b85654c921 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 @@ -54,12 +54,24 @@ class ComponentListFragment : Fragment(R.layout.component_list_fragment) { private fun setUpComponentsRecyclerView() { val adapter = - ComponentsRecyclerViewAdapter(::onItemClick).apply { - submitList(viewModel.getComponentList()) - } - val recyclerView = requireView().findViewById(R.id.componentsRecyclerView) - recyclerView.adapter = adapter - recyclerView.layoutManager = GridLayoutManager(requireContext(), 2) + ComponentsRecyclerViewAdapter(::onItemClick).apply { submitList(viewModel.viewItemList) } + with(requireView().findViewById(R.id.componentsRecyclerView)) { + this.adapter = adapter + layoutManager = + GridLayoutManager(requireContext(), ComponentsRecyclerViewAdapter.ViewType.HEADER.spanCount) + .apply { + spanSizeLookup = + object : GridLayoutManager.SpanSizeLookup() { + override fun getSpanSize(position: Int): Int { + return if (adapter.getItemViewType(position) == + ComponentsRecyclerViewAdapter.ViewType.HEADER.ordinal + ) + ComponentsRecyclerViewAdapter.ViewType.HEADER.spanCount + else ComponentsRecyclerViewAdapter.ViewType.ITEM.spanCount + } + } + } + } } private fun onItemClick(component: ComponentListViewModel.Component) { diff --git a/catalog/src/main/java/com/google/android/fhir/catalog/ComponentListViewModel.kt b/catalog/src/main/java/com/google/android/fhir/catalog/ComponentListViewModel.kt index 71839e8a57..b8cfad1a92 100644 --- a/catalog/src/main/java/com/google/android/fhir/catalog/ComponentListViewModel.kt +++ b/catalog/src/main/java/com/google/android/fhir/catalog/ComponentListViewModel.kt @@ -25,8 +25,14 @@ import androidx.lifecycle.SavedStateHandle class ComponentListViewModel(application: Application, private val state: SavedStateHandle) : AndroidViewModel(application) { - fun getComponentList(): List { - return Component.values().toList() + sealed class ViewItem { + data class HeaderItem(val header: Header) : ViewItem() + data class ComponentItem(val component: Component) : ViewItem() + } + + enum class Header(@StringRes val textId: Int) { + WIDGETS(R.string.widgets), + MISC_COMPONENTS(R.string.misc_components) } enum class Component( @@ -95,6 +101,7 @@ class ComponentListViewModel(application: Application, private val state: SavedS "component_date_time_picker.json", "component_date_time_picker_with_validation.json" ), + // TODO https://github.com/google/android-fhir/issues/1260 // SLIDER( // R.drawable.ic_slider, @@ -114,5 +121,25 @@ class ComponentListViewModel(application: Application, private val state: SavedS R.string.component_name_repeated_group, "component_repeated_group.json", ), + HELP(R.drawable.ic_help, R.string.component_name_help, "component_help.json") } + + val viewItemList = + listOf( + ViewItem.HeaderItem(Header.WIDGETS), + ViewItem.ComponentItem(Component.BOOLEAN_CHOICE), + ViewItem.ComponentItem(Component.SINGLE_CHOICE), + ViewItem.ComponentItem(Component.MULTIPLE_CHOICE), + ViewItem.ComponentItem(Component.DROPDOWN), + ViewItem.ComponentItem(Component.MODAL), + ViewItem.ComponentItem(Component.OPEN_CHOICE), + ViewItem.ComponentItem(Component.TEXT_FIELD), + ViewItem.ComponentItem(Component.DATE_PICKER), + ViewItem.ComponentItem(Component.DATE_TIME_PICKER), + ViewItem.ComponentItem(Component.IMAGE), + ViewItem.ComponentItem(Component.AUTO_COMPLETE), + ViewItem.ComponentItem(Component.REPEATED_GROUP), + ViewItem.HeaderItem(Header.MISC_COMPONENTS), + ViewItem.ComponentItem(Component.HELP), + ) } diff --git a/catalog/src/main/java/com/google/android/fhir/catalog/ComponentsRecyclerViewadapter.kt b/catalog/src/main/java/com/google/android/fhir/catalog/ComponentsRecyclerViewadapter.kt index f3dc0fdd96..fe5881e647 100644 --- a/catalog/src/main/java/com/google/android/fhir/catalog/ComponentsRecyclerViewadapter.kt +++ b/catalog/src/main/java/com/google/android/fhir/catalog/ComponentsRecyclerViewadapter.kt @@ -1,5 +1,5 @@ /* - * Copyright 2021 Google LLC + * Copyright 2022 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,43 +21,81 @@ import android.view.ViewGroup import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView +import com.google.android.fhir.catalog.databinding.ComponentHeaderLayoutBinding import com.google.android.fhir.catalog.databinding.LandingPageItemBinding class ComponentsRecyclerViewAdapter( private val onItemClick: (ComponentListViewModel.Component) -> Unit -) : ListAdapter(ComponentDiffUtil()) { - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ComponentListViewHolder { - return ComponentListViewHolder( - LandingPageItemBinding.inflate(LayoutInflater.from(parent.context), parent, false), - onItemClick - ) +) : ListAdapter(ComponentDiffUtil()) { + + enum class ViewType(val spanCount: Int) { + HEADER(2), + ITEM(1) + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + return when (viewType) { + ViewType.HEADER.ordinal -> + ComponentHeaderViewHolder( + ComponentHeaderLayoutBinding.inflate(LayoutInflater.from(parent.context), parent, false) + ) + ViewType.ITEM.ordinal -> + ComponentListViewHolder( + LandingPageItemBinding.inflate(LayoutInflater.from(parent.context), parent, false), + onItemClick + ) + else -> throw IllegalArgumentException("$viewType must be ViewType.") + } + } + + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + if (holder is ComponentViewHolder) { + holder.bind(getItem(position)) + } } - override fun onBindViewHolder(holder: ComponentListViewHolder, position: Int) { - holder.bind(getItem(position)) + override fun getItemViewType(position: Int): Int { + return when (getItem(position)) { + is ComponentListViewModel.ViewItem.HeaderItem -> ViewType.HEADER.ordinal + is ComponentListViewModel.ViewItem.ComponentItem -> ViewType.ITEM.ordinal + } } } +interface ComponentViewHolder { + fun bind(component: ComponentListViewModel.ViewItem) +} + class ComponentListViewHolder( private val binding: LandingPageItemBinding, private val onItemClick: (ComponentListViewModel.Component) -> Unit -) : RecyclerView.ViewHolder(binding.root) { - fun bind(component: ComponentListViewModel.Component) { - binding.componentLayoutIconImageview.setImageResource(component.iconId) +) : RecyclerView.ViewHolder(binding.root), ComponentViewHolder { + override fun bind(component: ComponentListViewModel.ViewItem) { + val componentItem = component as ComponentListViewModel.ViewItem.ComponentItem + binding.componentLayoutIconImageview.setImageResource(componentItem.component.iconId) binding.componentLayoutTextView.text = - binding.componentLayoutTextView.context.getString(component.textId) - binding.root.setOnClickListener { onItemClick(component) } + binding.componentLayoutTextView.context.getString(componentItem.component.textId) + binding.root.setOnClickListener { onItemClick(component.component) } + } +} + +class ComponentHeaderViewHolder(private val binding: ComponentHeaderLayoutBinding) : + RecyclerView.ViewHolder(binding.root), ComponentViewHolder { + override fun bind(viewItem: ComponentListViewModel.ViewItem) { + val headerItem = viewItem as ComponentListViewModel.ViewItem.HeaderItem + binding.tvComponentHeader.text = + binding.tvComponentHeader.context.getString(headerItem.header.textId) } } -class ComponentDiffUtil : DiffUtil.ItemCallback() { +class ComponentDiffUtil : DiffUtil.ItemCallback() { override fun areItemsTheSame( - oldComponent: ComponentListViewModel.Component, - newComponent: ComponentListViewModel.Component + oldComponent: ComponentListViewModel.ViewItem, + newComponent: ComponentListViewModel.ViewItem ) = oldComponent === newComponent override fun areContentsTheSame( - oldComponent: ComponentListViewModel.Component, - newComponent: ComponentListViewModel.Component + oldComponent: ComponentListViewModel.ViewItem, + newComponent: ComponentListViewModel.ViewItem ) = oldComponent == newComponent } diff --git a/catalog/src/main/res/drawable/ic_help.xml b/catalog/src/main/res/drawable/ic_help.xml new file mode 100644 index 0000000000..0bd6ca59f8 --- /dev/null +++ b/catalog/src/main/res/drawable/ic_help.xml @@ -0,0 +1,13 @@ + + + diff --git a/catalog/src/main/res/layout/component_header_layout.xml b/catalog/src/main/res/layout/component_header_layout.xml new file mode 100644 index 0000000000..a5811a10d9 --- /dev/null +++ b/catalog/src/main/res/layout/component_header_layout.xml @@ -0,0 +1,18 @@ + + + + + diff --git a/catalog/src/main/res/values/dimens.xml b/catalog/src/main/res/values/dimens.xml index f2c66415cb..3516d07fd0 100644 --- a/catalog/src/main/res/values/dimens.xml +++ b/catalog/src/main/res/values/dimens.xml @@ -13,4 +13,6 @@ 8dp 16dp 8dp + 24dp + 12dp diff --git a/catalog/src/main/res/values/strings.xml b/catalog/src/main/res/values/strings.xml index 555662c376..4320f079d9 100644 --- a/catalog/src/main/res/values/strings.xml +++ b/catalog/src/main/res/values/strings.xml @@ -31,8 +31,9 @@ Dropdown Image Auto Complete + Help Repeated Group - Default + Default Paginated Review Read only @@ -60,4 +61,6 @@ Hide error state Options Error + Widgets + Miscellaneous components