@@ -21,31 +21,26 @@ import android.os.Bundle
2121import android.view.LayoutInflater
2222import android.view.View
2323import android.view.ViewGroup
24- import android.widget.LinearLayout
2524import android.widget.TextView
2625import androidx.annotation.VisibleForTesting
2726import androidx.appcompat.view.ContextThemeWrapper
28- import androidx.compose.foundation.layout.fillMaxWidth
29- import androidx.compose.foundation.lazy.LazyColumn
30- import androidx.compose.foundation.lazy.items
31- import androidx.compose.runtime.Composable
32- import androidx.compose.ui.Modifier
3327import androidx.compose.ui.platform.ComposeView
34- import androidx.compose.ui.viewinterop.AndroidView
3528import androidx.core.content.res.use
3629import androidx.core.os.bundleOf
3730import androidx.fragment.app.Fragment
3831import androidx.fragment.app.activityViewModels
3932import androidx.fragment.app.setFragmentResult
4033import androidx.fragment.app.viewModels
34+ import androidx.lifecycle.Lifecycle
4135import androidx.lifecycle.lifecycleScope
42- import androidx.recyclerview.widget.LinearLayoutManager
43- import androidx.recyclerview.widget.RecyclerView
44- import com.google.android.fhir.datacapture.extensions.inflate
36+ import androidx.lifecycle.repeatOnLifecycle
37+ import com.google.android.fhir.datacapture.QuestionnaireFragment.Companion.EXTRA_QUESTIONNAIRE_JSON_STRING
38+ import com.google.android.fhir.datacapture.QuestionnaireFragment.Companion.EXTRA_QUESTIONNAIRE_JSON_URI
39+ import com.google.android.fhir.datacapture.QuestionnaireFragment.Companion.EXTRA_QUESTIONNAIRE_RESPONSE_JSON_STRING
40+ import com.google.android.fhir.datacapture.QuestionnaireFragment.Companion.EXTRA_QUESTIONNAIRE_RESPONSE_JSON_URI
4541import com.google.android.fhir.datacapture.validation.Invalid
4642import com.google.android.fhir.datacapture.views.NavigationViewHolder
4743import com.google.android.fhir.datacapture.views.factories.QuestionnaireItemViewHolderFactory
48- import com.google.android.fhir.datacapture.views.factories.ReviewViewHolderFactory
4944import com.google.android.material.progressindicator.LinearProgressIndicator
5045import kotlinx.coroutines.launch
5146import org.hl7.fhir.r4.model.Questionnaire
@@ -101,8 +96,8 @@ class QuestionnaireFragment : Fragment() {
10196
10297 /* * @suppress */
10398 override fun onViewCreated (view : View , savedInstanceState : Bundle ? ) {
104- val questionnaireEditRecyclerView =
105- view.findViewById<RecyclerView >(R .id.questionnaire_edit_recycler_view )
99+ val questionnaireEditComposeView =
100+ view.findViewById<ComposeView >(R .id.questionnaire_edit_compose_view )
106101 val questionnaireReviewComposeView =
107102 view.findViewById<ComposeView >(R .id.questionnaire_review_recycler_view)
108103 val questionnaireTitle = view.findViewById<TextView >(R .id.questionnaire_title)
@@ -147,103 +142,97 @@ class QuestionnaireFragment : Fragment() {
147142 }
148143 val questionnaireProgressIndicator: LinearProgressIndicator =
149144 view.findViewById(R .id.questionnaire_progress_indicator)
150- val questionnaireEditAdapter =
151- QuestionnaireEditAdapter (questionnaireItemViewHolderFactoryMatchersProvider.get())
152145
153146 val reviewModeEditButton =
154147 view.findViewById<View >(R .id.review_mode_edit_button).apply {
155148 setOnClickListener { viewModel.setReviewMode(false ) }
156149 }
157150
158- questionnaireEditRecyclerView.adapter = questionnaireEditAdapter
159- val linearLayoutManager = LinearLayoutManager (view.context)
160- questionnaireEditRecyclerView.layoutManager = linearLayoutManager
161- // Animation does work well with views that could gain focus
162- questionnaireEditRecyclerView.itemAnimator = null
163-
164151 // Listen to updates from the view model.
165- viewLifecycleOwner.lifecycleScope.launchWhenCreated {
166- viewModel.questionnaireStateFlow.collect { state ->
167- when (val displayMode = state.displayMode) {
168- is DisplayMode .ReviewMode -> {
169- // Set items
170- questionnaireEditRecyclerView.visibility = View .GONE
171-
172- questionnaireReviewComposeView.visibility = View .VISIBLE
173- questionnaireReviewComposeView.setContent { QuestionnaireReviewList (state.items) }
174- reviewModeEditButton.visibility =
175- if (displayMode.showEditButton) {
176- View .VISIBLE
152+ viewLifecycleOwner.lifecycleScope.launch {
153+ viewLifecycleOwner.repeatOnLifecycle(Lifecycle .State .CREATED ) {
154+ viewModel.questionnaireStateFlow.collect { state ->
155+ when (val displayMode = state.displayMode) {
156+ is DisplayMode .ReviewMode -> {
157+ // Set items
158+
159+ questionnaireReviewComposeView.visibility = View .VISIBLE
160+ questionnaireReviewComposeView.setContent { QuestionnaireReviewList (state.items) }
161+ questionnaireEditComposeView.visibility = View .GONE
162+
163+ reviewModeEditButton.visibility =
164+ if (displayMode.showEditButton) {
165+ View .VISIBLE
166+ } else {
167+ View .GONE
168+ }
169+ questionnaireTitle.visibility = View .VISIBLE
170+ questionnaireTitle.text = getString(R .string.questionnaire_review_mode_title)
171+
172+ // Set bottom navigation
173+ if (state.bottomNavItem != null ) {
174+ bottomNavContainerFrame.visibility = View .VISIBLE
175+ NavigationViewHolder (bottomNavContainerFrame)
176+ .bind(state.bottomNavItem.questionnaireNavigationUIState)
177177 } else {
178- View .GONE
178+ bottomNavContainerFrame.visibility = View .GONE
179179 }
180- questionnaireTitle.visibility = View .VISIBLE
181- questionnaireTitle.text = getString(R .string.questionnaire_review_mode_title)
182-
183- // Set bottom navigation
184- if (state.bottomNavItem != null ) {
185- bottomNavContainerFrame.visibility = View .VISIBLE
186- NavigationViewHolder (bottomNavContainerFrame)
187- .bind(state.bottomNavItem.questionnaireNavigationUIState)
188- } else {
189- bottomNavContainerFrame.visibility = View .GONE
190- }
191180
192- // Hide progress indicator
193- questionnaireProgressIndicator.visibility = View .GONE
194- }
195- is DisplayMode .EditMode -> {
196- // Set items
197- questionnaireReviewComposeView.visibility = View .GONE
198- questionnaireEditAdapter.submitList(state.items)
199- questionnaireEditRecyclerView.visibility = View .VISIBLE
200- reviewModeEditButton.visibility = View .GONE
201- questionnaireTitle.visibility = View .GONE
202-
203- // Set bottom navigation
204- if (state.bottomNavItem != null ) {
205- bottomNavContainerFrame.visibility = View .VISIBLE
206- NavigationViewHolder (bottomNavContainerFrame)
207- .bind(state.bottomNavItem.questionnaireNavigationUIState)
208- } else {
209- bottomNavContainerFrame.visibility = View .GONE
181+ // Hide progress indicator
182+ questionnaireProgressIndicator.visibility = View .GONE
210183 }
211-
212- // Set progress indicator
213- questionnaireProgressIndicator.visibility = View .VISIBLE
214- if (displayMode.pagination.isPaginated) {
215- questionnaireProgressIndicator.updateProgressIndicator(
216- calculateProgressPercentage(
217- count =
218- (displayMode.pagination.currentPageIndex +
219- 1 ), // incremented by 1 due to initialPageIndex starts with 0.
220- totalCount = displayMode.pagination.pages.size,
221- ),
222- )
223- } else {
224- questionnaireEditRecyclerView.addOnScrollListener(
225- object : RecyclerView .OnScrollListener () {
226- override fun onScrolled (recyclerView : RecyclerView , dx : Int , dy : Int ) {
227- super .onScrolled(recyclerView, dx, dy)
184+ is DisplayMode .EditMode -> {
185+ // Set items
186+ questionnaireReviewComposeView.visibility = View .GONE
187+ questionnaireEditComposeView.setContent {
188+ QuestionnaireEditList (
189+ items = state.items,
190+ displayMode = displayMode,
191+ questionnaireItemViewHolderMatchers =
192+ questionnaireItemViewHolderFactoryMatchersProvider.get(),
193+ onUpdateProgressIndicator = { currentPage, totalCount ->
228194 questionnaireProgressIndicator.updateProgressIndicator(
229195 calculateProgressPercentage(
230- count =
231- (linearLayoutManager.findLastVisibleItemPosition() +
232- 1 ), // incremented by 1 due to findLastVisiblePosition() starts with 0.
233- totalCount = linearLayoutManager.itemCount,
196+ count = (currentPage + 1 ),
197+ totalCount = totalCount,
234198 ),
235199 )
236- }
237- },
238- )
200+ },
201+ )
202+ }
203+ questionnaireEditComposeView.visibility = View .VISIBLE
204+ reviewModeEditButton.visibility = View .GONE
205+ questionnaireTitle.visibility = View .GONE
206+
207+ // Set bottom navigation
208+ if (state.bottomNavItem != null ) {
209+ bottomNavContainerFrame.visibility = View .VISIBLE
210+ NavigationViewHolder (bottomNavContainerFrame)
211+ .bind(state.bottomNavItem.questionnaireNavigationUIState)
212+ } else {
213+ bottomNavContainerFrame.visibility = View .GONE
214+ }
215+
216+ // Set progress indicator
217+ questionnaireProgressIndicator.visibility = View .VISIBLE
218+ if (displayMode.pagination.isPaginated) {
219+ questionnaireProgressIndicator.updateProgressIndicator(
220+ calculateProgressPercentage(
221+ count =
222+ (displayMode.pagination.currentPageIndex +
223+ 1 ), // incremented by 1 due to initialPageIndex starts with 0.
224+ totalCount = displayMode.pagination.pages.size,
225+ ),
226+ )
227+ }
228+ }
229+ is DisplayMode .InitMode -> {
230+ questionnaireReviewComposeView.visibility = View .GONE
231+ questionnaireEditComposeView.visibility = View .GONE
232+ questionnaireProgressIndicator.visibility = View .GONE
233+ reviewModeEditButton.visibility = View .GONE
234+ bottomNavContainerFrame.visibility = View .GONE
239235 }
240- }
241- is DisplayMode .InitMode -> {
242- questionnaireReviewComposeView.visibility = View .GONE
243- questionnaireEditRecyclerView.visibility = View .GONE
244- questionnaireProgressIndicator.visibility = View .GONE
245- reviewModeEditButton.visibility = View .GONE
246- bottomNavContainerFrame.visibility = View .GONE
247236 }
248237 }
249238 }
@@ -288,53 +277,6 @@ class QuestionnaireFragment : Fragment() {
288277 }
289278 }
290279
291- @Composable
292- private fun QuestionnaireReviewList (items : List <QuestionnaireAdapterItem >) {
293- LazyColumn {
294- items(
295- items = items,
296- key = { item ->
297- when (item) {
298- is QuestionnaireAdapterItem .Question -> item.id
299- ? : throw IllegalStateException (" Missing id for the Question: $item " )
300- is QuestionnaireAdapterItem .RepeatedGroupHeader -> item.id
301- is QuestionnaireAdapterItem .Navigation -> " navigation"
302- is QuestionnaireAdapterItem .RepeatedGroupAddButton -> item.id
303- ? : throw IllegalStateException (" Missing id for the RepeatedGroupAddButton: $item " )
304- }
305- },
306- ) { item: QuestionnaireAdapterItem ->
307- AndroidView (
308- factory = { context ->
309- LinearLayout (context).apply {
310- orientation = LinearLayout .VERTICAL
311- when (item) {
312- is QuestionnaireAdapterItem .Question -> {
313- val viewHolder = ReviewViewHolderFactory .create(this )
314- viewHolder.bind(item.item)
315- addView(viewHolder.itemView)
316- }
317- is QuestionnaireAdapterItem .Navigation -> {
318- val viewHolder =
319- NavigationViewHolder (inflate(R .layout.pagination_navigation_view))
320- viewHolder.bind(item.questionnaireNavigationUIState)
321- addView(viewHolder.itemView)
322- }
323- is QuestionnaireAdapterItem .RepeatedGroupHeader -> {
324- TODO (" Not implemented yet" )
325- }
326- is QuestionnaireAdapterItem .RepeatedGroupAddButton -> {
327- TODO (" Not implemented yet" )
328- }
329- }
330- }
331- },
332- modifier = Modifier .fillMaxWidth(),
333- )
334- }
335- }
336- }
337-
338280 /* * Calculates the progress percentage from given [count] and [totalCount] values. */
339281 internal fun calculateProgressPercentage (count : Int , totalCount : Int ): Int {
340282 return if (totalCount == 0 ) 0 else (count * 100 / totalCount)
@@ -589,6 +531,9 @@ class QuestionnaireFragment : Fragment() {
589531 */
590532 internal const val EXTRA_SHOW_SUBMIT_ANYWAY_BUTTON = " show-submit-anyway-button"
591533
534+ /* * Test tag for QuestionnaireEditList */
535+ const val QUESTIONNAIRE_EDIT_LIST = " questionnaire_edit_list"
536+
592537 fun builder () = Builder ()
593538 }
594539
0 commit comments