From b31e401bd3eff65a97314601b4e6569da2011686 Mon Sep 17 00:00:00 2001 From: Grzegorz Orczykowski Date: Sat, 13 Jan 2024 12:11:31 +0100 Subject: [PATCH 1/8] Added failing test --- .../geo/selection/SelectionMapFragmentTest.kt | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/geo/src/test/java/org/odk/collect/geo/selection/SelectionMapFragmentTest.kt b/geo/src/test/java/org/odk/collect/geo/selection/SelectionMapFragmentTest.kt index aeb7378f195..d3dc0d5cc09 100644 --- a/geo/src/test/java/org/odk/collect/geo/selection/SelectionMapFragmentTest.kt +++ b/geo/src/test/java/org/odk/collect/geo/selection/SelectionMapFragmentTest.kt @@ -804,6 +804,40 @@ class SelectionMapFragmentTest { scenario.moveToState(Lifecycle.State.DESTROYED) } + @Test // https://github.com/getodk/collect/issues/5540 + fun `opening the map with already selected item when skipSummary is true does not close the map`() { + val items = listOf( + Fixtures.actionMappableSelectItem().copy(id = 0, points = listOf(MapPoint(40.0, 0.0))), + Fixtures.actionMappableSelectItem().copy(id = 1, points = listOf(MapPoint(41.0, 0.0)), selected = true) + ) + whenever(data.getMappableItems()).thenReturn(MutableLiveData(items)) + + val scenario = launcherRule.launchInContainer( + SelectionMapFragment::class.java, + factory = FragmentFactoryBuilder() + .forClass(SelectionMapFragment::class.java) { + SelectionMapFragment( + data, + skipSummary = true, + onBackPressedDispatcher = { onBackPressedDispatcher } + ) + }.build() + ) + var actualResult: Bundle? = null + scenario.onFragment { + it.parentFragmentManager.setFragmentResultListener( + SelectionMapFragment.REQUEST_SELECT_ITEM, + it + ) { _: String?, result: Bundle -> + actualResult = result + } + } + + map.ready() + + assertThat(actualResult, equalTo(null)) + } + private fun MappableSelectItem.toMapPoint(): MapPoint { return MapPoint(this.points[0].latitude, this.points[0].longitude) } From 8ad327a1f720a53b419cb5ad6bfdc690516b7dcf Mon Sep 17 00:00:00 2001 From: Grzegorz Orczykowski Date: Sat, 13 Jan 2024 12:21:11 +0100 Subject: [PATCH 2/8] Fixed closing the map when the quick appearance is used and there is a selected item --- .../geo/selection/SelectionMapFragment.kt | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/geo/src/main/java/org/odk/collect/geo/selection/SelectionMapFragment.kt b/geo/src/main/java/org/odk/collect/geo/selection/SelectionMapFragment.kt index 810c3c7b406..f54d52880cd 100644 --- a/geo/src/main/java/org/odk/collect/geo/selection/SelectionMapFragment.kt +++ b/geo/src/main/java/org/odk/collect/geo/selection/SelectionMapFragment.kt @@ -265,7 +265,7 @@ class SelectionMapFragment( } } - private fun onFeatureClicked(featureId: Int, maintainZoom: Boolean = true) { + private fun onFeatureClicked(featureId: Int, maintainZoom: Boolean = true, selectedByUser: Boolean = true) { val item = itemsByFeatureId[featureId] val selectedItem = selectedItemViewModel.getSelectedItem() @@ -274,7 +274,14 @@ class SelectionMapFragment( resetIcon(selectedItem) } - if (!skipSummary) { + if (skipSummary && selectedByUser) { + parentFragmentManager.setFragmentResult( + REQUEST_SELECT_ITEM, + Bundle().also { + it.putLong(RESULT_SELECTED_ITEM, item.id) + } + ) + } else { if (item.points.size > 1) { map.zoomToBoundingBox(item.points, 0.8, true) } else { @@ -305,13 +312,6 @@ class SelectionMapFragment( ) selectedItemViewModel.setSelectedItem(item) - } else { - parentFragmentManager.setFragmentResult( - REQUEST_SELECT_ITEM, - Bundle().also { - it.putLong(RESULT_SELECTED_ITEM, item.id) - } - ) } } } @@ -337,7 +337,7 @@ class SelectionMapFragment( onFeatureClicked(featureId) } } else if (previouslySelectedItem != null) { - onFeatureClicked(previouslySelectedItem, maintainZoom = false) + onFeatureClicked(previouslySelectedItem, maintainZoom = false, selectedByUser = false) } else if (!map.hasCenter()) { if (zoomToFitItems && points.isNotEmpty()) { map.zoomToBoundingBox(points, 0.8, false) From 3089407f5fcca385e6c43fee42354924c1abc2fe Mon Sep 17 00:00:00 2001 From: Grzegorz Orczykowski Date: Sat, 13 Jan 2024 12:44:36 +0100 Subject: [PATCH 3/8] Added a failing test for recreating the map --- .../geo/selection/SelectionMapFragmentTest.kt | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/geo/src/test/java/org/odk/collect/geo/selection/SelectionMapFragmentTest.kt b/geo/src/test/java/org/odk/collect/geo/selection/SelectionMapFragmentTest.kt index d3dc0d5cc09..934e06d2fa3 100644 --- a/geo/src/test/java/org/odk/collect/geo/selection/SelectionMapFragmentTest.kt +++ b/geo/src/test/java/org/odk/collect/geo/selection/SelectionMapFragmentTest.kt @@ -838,6 +838,41 @@ class SelectionMapFragmentTest { assertThat(actualResult, equalTo(null)) } + @Test // https://github.com/getodk/collect/issues/5540 + fun `recreating the map with already selected item when skipSummary is true does not close the map`() { + val items = listOf( + Fixtures.actionMappableSelectItem().copy(id = 0, points = listOf(MapPoint(40.0, 0.0))), + Fixtures.actionMappableSelectItem().copy(id = 1, points = listOf(MapPoint(41.0, 0.0)), selected = true) + ) + whenever(data.getMappableItems()).thenReturn(MutableLiveData(items)) + + val scenario = launcherRule.launchInContainer( + SelectionMapFragment::class.java, + factory = FragmentFactoryBuilder() + .forClass(SelectionMapFragment::class.java) { + SelectionMapFragment( + data, + skipSummary = true, + onBackPressedDispatcher = { onBackPressedDispatcher } + ) + }.build() + ) + map.ready() + scenario.recreate() + var actualResult: Bundle? = null + scenario.onFragment { + it.parentFragmentManager.setFragmentResultListener( + SelectionMapFragment.REQUEST_SELECT_ITEM, + it + ) { _: String?, result: Bundle -> + actualResult = result + } + } + map.ready() + + assertThat(actualResult, equalTo(null)) + } + private fun MappableSelectItem.toMapPoint(): MapPoint { return MapPoint(this.points[0].latitude, this.points[0].longitude) } From 39b75bb627d8e6def17b97505b3ddb7983eea6cf Mon Sep 17 00:00:00 2001 From: Grzegorz Orczykowski Date: Sat, 13 Jan 2024 12:45:08 +0100 Subject: [PATCH 4/8] Fixed recreating the map when the quick appearance is used and there is a selected item --- .../java/org/odk/collect/geo/selection/SelectionMapFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geo/src/main/java/org/odk/collect/geo/selection/SelectionMapFragment.kt b/geo/src/main/java/org/odk/collect/geo/selection/SelectionMapFragment.kt index f54d52880cd..bf72f294cb4 100644 --- a/geo/src/main/java/org/odk/collect/geo/selection/SelectionMapFragment.kt +++ b/geo/src/main/java/org/odk/collect/geo/selection/SelectionMapFragment.kt @@ -334,7 +334,7 @@ class SelectionMapFragment( if (selectedItem != null) { val featureId = featureIdsByItemId[selectedItem.id] if (featureId != null) { - onFeatureClicked(featureId) + onFeatureClicked(featureId, selectedByUser = false) } } else if (previouslySelectedItem != null) { onFeatureClicked(previouslySelectedItem, maintainZoom = false, selectedByUser = false) From d3485585ddfdf8bcac0c28ef25abd7488cee7753 Mon Sep 17 00:00:00 2001 From: Grzegorz Orczykowski Date: Sat, 13 Jan 2024 12:45:39 +0100 Subject: [PATCH 5/8] NAming improvements --- .../odk/collect/geo/selection/SelectionMapFragment.kt | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/geo/src/main/java/org/odk/collect/geo/selection/SelectionMapFragment.kt b/geo/src/main/java/org/odk/collect/geo/selection/SelectionMapFragment.kt index bf72f294cb4..64322ede7cd 100644 --- a/geo/src/main/java/org/odk/collect/geo/selection/SelectionMapFragment.kt +++ b/geo/src/main/java/org/odk/collect/geo/selection/SelectionMapFragment.kt @@ -22,7 +22,6 @@ import org.odk.collect.androidshared.ui.FragmentFactoryBuilder import org.odk.collect.androidshared.ui.ToastUtils import org.odk.collect.androidshared.ui.multiclicksafe.setMultiClickSafeOnClickListener import org.odk.collect.geo.GeoDependencyComponentProvider -import org.odk.collect.geo.R import org.odk.collect.geo.ReferenceLayerSettingsNavigator import org.odk.collect.geo.databinding.SelectionMapLayoutBinding import org.odk.collect.maps.MapFragment @@ -197,7 +196,7 @@ class SelectionMapFragment( map.setGpsLocationEnabled(true) - map.setFeatureClickListener(::onFeatureClicked) + map.setFeatureClickListener(::onFeatureSelected) map.setClickListener { onClick() } selectionMapData.getMappableItems().observe(viewLifecycleOwner) { @@ -265,7 +264,7 @@ class SelectionMapFragment( } } - private fun onFeatureClicked(featureId: Int, maintainZoom: Boolean = true, selectedByUser: Boolean = true) { + private fun onFeatureSelected(featureId: Int, maintainZoom: Boolean = true, selectedByUser: Boolean = true) { val item = itemsByFeatureId[featureId] val selectedItem = selectedItemViewModel.getSelectedItem() @@ -334,10 +333,10 @@ class SelectionMapFragment( if (selectedItem != null) { val featureId = featureIdsByItemId[selectedItem.id] if (featureId != null) { - onFeatureClicked(featureId, selectedByUser = false) + onFeatureSelected(featureId, selectedByUser = false) } } else if (previouslySelectedItem != null) { - onFeatureClicked(previouslySelectedItem, maintainZoom = false, selectedByUser = false) + onFeatureSelected(previouslySelectedItem, maintainZoom = false, selectedByUser = false) } else if (!map.hasCenter()) { if (zoomToFitItems && points.isNotEmpty()) { map.zoomToBoundingBox(points, 0.8, false) From 93c933902a25ebbeecc4811c2901cfd9501ea40e Mon Sep 17 00:00:00 2001 From: Grzegorz Orczykowski Date: Sat, 13 Jan 2024 14:53:44 +0100 Subject: [PATCH 6/8] Add support for the quick appearance in SelectOneFromMapWidget --- .../android/widgets/WidgetFactory.java | 2 +- .../widgets/items/SelectOneFromMapWidget.kt | 16 ++++- .../items/SelectOneFromMapWidgetTest.kt | 67 +++++++++++++++---- 3 files changed, 69 insertions(+), 16 deletions(-) diff --git a/collect_app/src/main/java/org/odk/collect/android/widgets/WidgetFactory.java b/collect_app/src/main/java/org/odk/collect/android/widgets/WidgetFactory.java index 9ed04ad7cb8..b21d324b042 100644 --- a/collect_app/src/main/java/org/odk/collect/android/widgets/WidgetFactory.java +++ b/collect_app/src/main/java/org/odk/collect/android/widgets/WidgetFactory.java @@ -315,7 +315,7 @@ private QuestionWidget getSelectOneWidget(String appearance, QuestionDetails que } else if (appearance.contains(Appearances.IMAGE_MAP)) { questionWidget = new SelectOneImageMapWidget(activity, questionDetails, isQuick, formEntryViewModel); } else if (appearance.contains(Appearances.MAP)) { - questionWidget = new SelectOneFromMapWidget(activity, questionDetails); + questionWidget = new SelectOneFromMapWidget(activity, questionDetails, isQuick); } else { questionWidget = new SelectOneWidget(activity, questionDetails, isQuick, formController, formEntryViewModel); } diff --git a/collect_app/src/main/java/org/odk/collect/android/widgets/items/SelectOneFromMapWidget.kt b/collect_app/src/main/java/org/odk/collect/android/widgets/items/SelectOneFromMapWidget.kt index c34f9422807..8b37c5926b4 100644 --- a/collect_app/src/main/java/org/odk/collect/android/widgets/items/SelectOneFromMapWidget.kt +++ b/collect_app/src/main/java/org/odk/collect/android/widgets/items/SelectOneFromMapWidget.kt @@ -14,6 +14,7 @@ import org.javarosa.core.model.data.helper.Selection import org.javarosa.form.api.FormEntryPrompt import org.odk.collect.android.databinding.SelectOneFromMapWidgetAnswerBinding import org.odk.collect.android.formentry.questions.QuestionDetails +import org.odk.collect.android.listeners.AdvanceToNextListener import org.odk.collect.android.widgets.QuestionWidget import org.odk.collect.android.widgets.interfaces.WidgetDataReceiver import org.odk.collect.android.widgets.items.SelectOneFromMapDialogFragment.Companion.ARG_FORM_INDEX @@ -22,10 +23,18 @@ import org.odk.collect.androidshared.ui.DialogFragmentUtils import org.odk.collect.permissions.PermissionListener @SuppressLint("ViewConstructor") -class SelectOneFromMapWidget(context: Context, questionDetails: QuestionDetails) : - QuestionWidget(context, questionDetails), WidgetDataReceiver { +class SelectOneFromMapWidget( + context: Context, + questionDetails: QuestionDetails, + private val autoAdvance: Boolean +) : QuestionWidget(context, questionDetails), WidgetDataReceiver { + + lateinit var autoAdvanceListener: AdvanceToNextListener init { + if (context is AdvanceToNextListener) { + autoAdvanceListener = context + } render() } @@ -79,6 +88,9 @@ class SelectOneFromMapWidget(context: Context, questionDetails: QuestionDetails) override fun setData(answer: Any?) { updateAnswer(answer as SelectOneData) widgetValueChanged() + if (autoAdvance) { + autoAdvanceListener.advance() + } } private fun updateAnswer(answer: SelectOneData?) { diff --git a/collect_app/src/test/java/org/odk/collect/android/widgets/items/SelectOneFromMapWidgetTest.kt b/collect_app/src/test/java/org/odk/collect/android/widgets/items/SelectOneFromMapWidgetTest.kt index c087ecda789..76e49025777 100644 --- a/collect_app/src/test/java/org/odk/collect/android/widgets/items/SelectOneFromMapWidgetTest.kt +++ b/collect_app/src/test/java/org/odk/collect/android/widgets/items/SelectOneFromMapWidgetTest.kt @@ -16,11 +16,13 @@ import org.junit.runner.RunWith import org.mockito.kotlin.doReturn import org.mockito.kotlin.mock import org.mockito.kotlin.verify +import org.mockito.kotlin.verifyNoInteractions import org.mockito.kotlin.whenever import org.odk.collect.android.fakes.FakePermissionsProvider import org.odk.collect.android.formentry.FormEntryViewModel import org.odk.collect.android.formentry.questions.QuestionDetails import org.odk.collect.android.injection.config.AppDependencyModule +import org.odk.collect.android.listeners.AdvanceToNextListener import org.odk.collect.android.preferences.GuidanceHint import org.odk.collect.android.support.CollectHelpers import org.odk.collect.android.support.MockFormEntryPromptBuilder @@ -81,7 +83,8 @@ class SelectOneFromMapWidgetTest { val settings = settingsProvider.getUnprotectedSettings() val widget = SelectOneFromMapWidget( activityController.get(), - QuestionDetails(promptWithAnswer(null)) + QuestionDetails(promptWithAnswer(null)), + false ) assertThat( @@ -106,7 +109,7 @@ class SelectOneFromMapWidgetTest { val prompt = promptWithAnswer(null) val widget = - SelectOneFromMapWidget(activity, QuestionDetails(prompt)) + SelectOneFromMapWidget(activity, QuestionDetails(prompt), false) whenever(formEntryViewModel.getQuestionPrompt(prompt.index)).doReturn(prompt) widget.binding.button.performClick() @@ -127,7 +130,8 @@ class SelectOneFromMapWidgetTest { fun `clicking button when location permissions denied does nothing`() { val widget = SelectOneFromMapWidget( activityController.get(), - QuestionDetails(promptWithAnswer(null)) + QuestionDetails(promptWithAnswer(null)), + false ) permissionsProvider.setPermissionGranted(false) @@ -149,7 +153,7 @@ class SelectOneFromMapWidgetTest { .withAnswer(SelectOneData(choices[0].selection())) .build() - val widget = SelectOneFromMapWidget(activityController.get(), QuestionDetails(prompt)) + val widget = SelectOneFromMapWidget(activityController.get(), QuestionDetails(prompt), false) assertThat(widget.binding.answer.text, equalTo("A")) } @@ -158,7 +162,8 @@ class SelectOneFromMapWidgetTest { val settings = settingsProvider.getUnprotectedSettings() val widget = SelectOneFromMapWidget( activityController.get(), - QuestionDetails(promptWithAnswer(null)) + QuestionDetails(promptWithAnswer(null)), + false ) assertThat( @@ -174,7 +179,8 @@ class SelectOneFromMapWidgetTest { val widget = SelectOneFromMapWidget( activityController.get(), - QuestionDetails(promptWithAnswer(answer)) + QuestionDetails(promptWithAnswer(answer)), + false ) assertThat(widget.answer, equalTo(answer)) } @@ -186,7 +192,8 @@ class SelectOneFromMapWidgetTest { val widget = SelectOneFromMapWidget( activityController.get(), - QuestionDetails(promptWithAnswer(answer)) + QuestionDetails(promptWithAnswer(answer)), + false ) widget.clearAnswer() assertThat(widget.answer, equalTo(null)) @@ -199,7 +206,8 @@ class SelectOneFromMapWidgetTest { val widget = SelectOneFromMapWidget( activityController.get(), - QuestionDetails(promptWithAnswer(answer)) + QuestionDetails(promptWithAnswer(answer)), + false ) val mockValueChangedListener = mockValueChangedListener(widget) @@ -216,7 +224,7 @@ class SelectOneFromMapWidgetTest { .withAnswer(SelectOneData(choices[0].selection())) .build() - val widget = SelectOneFromMapWidget(activityController.get(), QuestionDetails(prompt)) + val widget = SelectOneFromMapWidget(activityController.get(), QuestionDetails(prompt), false) widget.clearAnswer() assertThat(widget.binding.answer.text, equalTo("")) @@ -226,7 +234,8 @@ class SelectOneFromMapWidgetTest { fun `setData sets answer`() { val widget = SelectOneFromMapWidget( activityController.get(), - QuestionDetails(promptWithAnswer(null)) + QuestionDetails(promptWithAnswer(null)), + false ) val selectChoice = selectChoice(value = "a", index = 101) @@ -244,7 +253,7 @@ class SelectOneFromMapWidgetTest { mapOf(choices[0] to "A", choices[1] to "B") ) .build() - val widget = SelectOneFromMapWidget(activityController.get(), QuestionDetails(prompt)) + val widget = SelectOneFromMapWidget(activityController.get(), QuestionDetails(prompt), false) widget.setData(SelectOneData(choices[1].selection())) assertThat(widget.binding.answer.text, equalTo("B")) @@ -258,7 +267,7 @@ class SelectOneFromMapWidgetTest { .withSelectChoiceText(mapOf(choices[0] to "A")) .build() - val widget = SelectOneFromMapWidget(activityController.get(), QuestionDetails(prompt)) + val widget = SelectOneFromMapWidget(activityController.get(), QuestionDetails(prompt), false) val mockValueChangedListener = mockValueChangedListener(widget) widget.setData(SelectOneData(choices[0].selection())) @@ -286,7 +295,7 @@ class SelectOneFromMapWidgetTest { .build() val widget = - SelectOneFromMapWidget(activity, QuestionDetails(prompt)) + SelectOneFromMapWidget(activity, QuestionDetails(prompt), false) widget.setData(SelectOneData(choices[1].selection())) whenever(formEntryViewModel.getQuestionPrompt(prompt.index)).doReturn(prompt) @@ -303,4 +312,36 @@ class SelectOneFromMapWidgetTest { equalTo(choices[1].index) ) } + + @Test + fun `setData calls AdvanceToNextListener when the 'quick' appearance is used`() { + val widget = SelectOneFromMapWidget( + activityController.get(), + QuestionDetails(promptWithAnswer(null)), + true + ) + val listener = mock() + widget.autoAdvanceListener = listener + + val selectChoice = selectChoice(value = "a", index = 101) + val answer = SelectOneData(selectChoice.selection()) + widget.setData(answer) + verify(listener).advance() + } + + @Test + fun `setData does not call AdvanceToNextListener when the 'quick' appearance is not used`() { + val widget = SelectOneFromMapWidget( + activityController.get(), + QuestionDetails(promptWithAnswer(null)), + false + ) + val listener = mock() + widget.autoAdvanceListener = listener + + val selectChoice = selectChoice(value = "a", index = 101) + val answer = SelectOneData(selectChoice.selection()) + widget.setData(answer) + verifyNoInteractions(listener) + } } From 2ac55825b2a0415788f7c0175573d370395c7c23 Mon Sep 17 00:00:00 2001 From: Grzegorz Orczykowski Date: Fri, 26 Jan 2024 14:47:50 +0100 Subject: [PATCH 7/8] Removed redundant links --- .../org/odk/collect/geo/selection/SelectionMapFragmentTest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/geo/src/test/java/org/odk/collect/geo/selection/SelectionMapFragmentTest.kt b/geo/src/test/java/org/odk/collect/geo/selection/SelectionMapFragmentTest.kt index 934e06d2fa3..4b4ff5b6d4a 100644 --- a/geo/src/test/java/org/odk/collect/geo/selection/SelectionMapFragmentTest.kt +++ b/geo/src/test/java/org/odk/collect/geo/selection/SelectionMapFragmentTest.kt @@ -804,7 +804,7 @@ class SelectionMapFragmentTest { scenario.moveToState(Lifecycle.State.DESTROYED) } - @Test // https://github.com/getodk/collect/issues/5540 + @Test fun `opening the map with already selected item when skipSummary is true does not close the map`() { val items = listOf( Fixtures.actionMappableSelectItem().copy(id = 0, points = listOf(MapPoint(40.0, 0.0))), @@ -838,7 +838,7 @@ class SelectionMapFragmentTest { assertThat(actualResult, equalTo(null)) } - @Test // https://github.com/getodk/collect/issues/5540 + @Test fun `recreating the map with already selected item when skipSummary is true does not close the map`() { val items = listOf( Fixtures.actionMappableSelectItem().copy(id = 0, points = listOf(MapPoint(40.0, 0.0))), From 345da30e54b3093240f7d3d5eb94b20f8f4078d0 Mon Sep 17 00:00:00 2001 From: Grzegorz Orczykowski Date: Fri, 26 Jan 2024 15:27:18 +0100 Subject: [PATCH 8/8] Pass the listener via constructor --- .../collect/android/formentry/ODKView.java | 4 +- .../android/widgets/WidgetFactory.java | 9 +++- .../widgets/items/SelectOneFromMapWidget.kt | 8 +--- .../android/widgets/WidgetFactoryTest.java | 2 +- .../items/SelectOneFromMapWidgetTest.kt | 45 +++++++++++-------- 5 files changed, 39 insertions(+), 29 deletions(-) diff --git a/collect_app/src/main/java/org/odk/collect/android/formentry/ODKView.java b/collect_app/src/main/java/org/odk/collect/android/formentry/ODKView.java index 5b6ce651c1b..2cc938c09a9 100644 --- a/collect_app/src/main/java/org/odk/collect/android/formentry/ODKView.java +++ b/collect_app/src/main/java/org/odk/collect/android/formentry/ODKView.java @@ -54,6 +54,7 @@ import org.javarosa.form.api.FormEntryCaption; import org.javarosa.form.api.FormEntryPrompt; import org.odk.collect.android.R; +import org.odk.collect.android.activities.FormFillingActivity; import org.odk.collect.android.application.Collect; import org.odk.collect.android.audio.AudioHelper; import org.odk.collect.android.exception.ExternalParamsException; @@ -196,7 +197,8 @@ public ODKView( viewLifecycle, new FileRequesterImpl(intentLauncher, externalAppIntentProvider, formController), new StringRequesterImpl(intentLauncher, externalAppIntentProvider, formController), - formController + formController, + (FormFillingActivity) context ); widgets = new ArrayList<>(); diff --git a/collect_app/src/main/java/org/odk/collect/android/widgets/WidgetFactory.java b/collect_app/src/main/java/org/odk/collect/android/widgets/WidgetFactory.java index b21d324b042..0b6f5977a1b 100644 --- a/collect_app/src/main/java/org/odk/collect/android/widgets/WidgetFactory.java +++ b/collect_app/src/main/java/org/odk/collect/android/widgets/WidgetFactory.java @@ -31,6 +31,7 @@ import org.odk.collect.android.formentry.questions.QuestionDetails; import org.odk.collect.android.geo.MapConfiguratorProvider; import org.odk.collect.android.javarosawrapper.FormController; +import org.odk.collect.android.listeners.AdvanceToNextListener; import org.odk.collect.android.storage.StoragePathProvider; import org.odk.collect.android.utilities.Appearances; import org.odk.collect.android.utilities.ExternalWebPageHelper; @@ -89,6 +90,7 @@ public class WidgetFactory { private final FileRequester fileRequester; private final StringRequester stringRequester; private final FormController formController; + private final AdvanceToNextListener advanceToNextListener; public WidgetFactory(Activity activity, boolean readOnlyOverride, @@ -103,7 +105,9 @@ public WidgetFactory(Activity activity, LifecycleOwner viewLifecycle, FileRequester fileRequester, StringRequester stringRequester, - FormController formController) { + FormController formController, + AdvanceToNextListener advanceToNextListener + ) { this.activity = activity; this.readOnlyOverride = readOnlyOverride; this.useExternalRecorder = useExternalRecorder; @@ -118,6 +122,7 @@ public WidgetFactory(Activity activity, this.fileRequester = fileRequester; this.stringRequester = stringRequester; this.formController = formController; + this.advanceToNextListener = advanceToNextListener; } public QuestionWidget createWidgetFromPrompt(FormEntryPrompt prompt, PermissionsProvider permissionsProvider) { @@ -315,7 +320,7 @@ private QuestionWidget getSelectOneWidget(String appearance, QuestionDetails que } else if (appearance.contains(Appearances.IMAGE_MAP)) { questionWidget = new SelectOneImageMapWidget(activity, questionDetails, isQuick, formEntryViewModel); } else if (appearance.contains(Appearances.MAP)) { - questionWidget = new SelectOneFromMapWidget(activity, questionDetails, isQuick); + questionWidget = new SelectOneFromMapWidget(activity, questionDetails, isQuick, advanceToNextListener); } else { questionWidget = new SelectOneWidget(activity, questionDetails, isQuick, formController, formEntryViewModel); } diff --git a/collect_app/src/main/java/org/odk/collect/android/widgets/items/SelectOneFromMapWidget.kt b/collect_app/src/main/java/org/odk/collect/android/widgets/items/SelectOneFromMapWidget.kt index 8b37c5926b4..bdae54e291f 100644 --- a/collect_app/src/main/java/org/odk/collect/android/widgets/items/SelectOneFromMapWidget.kt +++ b/collect_app/src/main/java/org/odk/collect/android/widgets/items/SelectOneFromMapWidget.kt @@ -26,15 +26,11 @@ import org.odk.collect.permissions.PermissionListener class SelectOneFromMapWidget( context: Context, questionDetails: QuestionDetails, - private val autoAdvance: Boolean + private val autoAdvance: Boolean, + private val autoAdvanceListener: AdvanceToNextListener ) : QuestionWidget(context, questionDetails), WidgetDataReceiver { - lateinit var autoAdvanceListener: AdvanceToNextListener - init { - if (context is AdvanceToNextListener) { - autoAdvanceListener = context - } render() } diff --git a/collect_app/src/test/java/org/odk/collect/android/widgets/WidgetFactoryTest.java b/collect_app/src/test/java/org/odk/collect/android/widgets/WidgetFactoryTest.java index 120d93911ab..4721556a489 100644 --- a/collect_app/src/test/java/org/odk/collect/android/widgets/WidgetFactoryTest.java +++ b/collect_app/src/test/java/org/odk/collect/android/widgets/WidgetFactoryTest.java @@ -37,7 +37,7 @@ public class WidgetFactoryTest { @Before public void setup() { Activity activity = CollectHelpers.buildThemedActivity(WidgetTestActivity.class).get(); - widgetFactory = new WidgetFactory(activity, false, false, null, null, null, null, mock(FormEntryViewModel.class), null, null, null, null, null, null); + widgetFactory = new WidgetFactory(activity, false, false, null, null, null, null, mock(FormEntryViewModel.class), null, null, null, null, null, null, mock()); } @Test diff --git a/collect_app/src/test/java/org/odk/collect/android/widgets/items/SelectOneFromMapWidgetTest.kt b/collect_app/src/test/java/org/odk/collect/android/widgets/items/SelectOneFromMapWidgetTest.kt index 76e49025777..88e89a95163 100644 --- a/collect_app/src/test/java/org/odk/collect/android/widgets/items/SelectOneFromMapWidgetTest.kt +++ b/collect_app/src/test/java/org/odk/collect/android/widgets/items/SelectOneFromMapWidgetTest.kt @@ -84,7 +84,8 @@ class SelectOneFromMapWidgetTest { val widget = SelectOneFromMapWidget( activityController.get(), QuestionDetails(promptWithAnswer(null)), - false + false, + mock() ) assertThat( @@ -109,7 +110,7 @@ class SelectOneFromMapWidgetTest { val prompt = promptWithAnswer(null) val widget = - SelectOneFromMapWidget(activity, QuestionDetails(prompt), false) + SelectOneFromMapWidget(activity, QuestionDetails(prompt), false, mock()) whenever(formEntryViewModel.getQuestionPrompt(prompt.index)).doReturn(prompt) widget.binding.button.performClick() @@ -131,7 +132,8 @@ class SelectOneFromMapWidgetTest { val widget = SelectOneFromMapWidget( activityController.get(), QuestionDetails(promptWithAnswer(null)), - false + false, + mock() ) permissionsProvider.setPermissionGranted(false) @@ -153,7 +155,7 @@ class SelectOneFromMapWidgetTest { .withAnswer(SelectOneData(choices[0].selection())) .build() - val widget = SelectOneFromMapWidget(activityController.get(), QuestionDetails(prompt), false) + val widget = SelectOneFromMapWidget(activityController.get(), QuestionDetails(prompt), false, mock()) assertThat(widget.binding.answer.text, equalTo("A")) } @@ -163,7 +165,8 @@ class SelectOneFromMapWidgetTest { val widget = SelectOneFromMapWidget( activityController.get(), QuestionDetails(promptWithAnswer(null)), - false + false, + mock() ) assertThat( @@ -180,7 +183,8 @@ class SelectOneFromMapWidgetTest { val widget = SelectOneFromMapWidget( activityController.get(), QuestionDetails(promptWithAnswer(answer)), - false + false, + mock() ) assertThat(widget.answer, equalTo(answer)) } @@ -193,7 +197,8 @@ class SelectOneFromMapWidgetTest { val widget = SelectOneFromMapWidget( activityController.get(), QuestionDetails(promptWithAnswer(answer)), - false + false, + mock() ) widget.clearAnswer() assertThat(widget.answer, equalTo(null)) @@ -207,7 +212,8 @@ class SelectOneFromMapWidgetTest { val widget = SelectOneFromMapWidget( activityController.get(), QuestionDetails(promptWithAnswer(answer)), - false + false, + mock() ) val mockValueChangedListener = mockValueChangedListener(widget) @@ -224,7 +230,7 @@ class SelectOneFromMapWidgetTest { .withAnswer(SelectOneData(choices[0].selection())) .build() - val widget = SelectOneFromMapWidget(activityController.get(), QuestionDetails(prompt), false) + val widget = SelectOneFromMapWidget(activityController.get(), QuestionDetails(prompt), false, mock()) widget.clearAnswer() assertThat(widget.binding.answer.text, equalTo("")) @@ -235,7 +241,8 @@ class SelectOneFromMapWidgetTest { val widget = SelectOneFromMapWidget( activityController.get(), QuestionDetails(promptWithAnswer(null)), - false + false, + mock() ) val selectChoice = selectChoice(value = "a", index = 101) @@ -253,7 +260,7 @@ class SelectOneFromMapWidgetTest { mapOf(choices[0] to "A", choices[1] to "B") ) .build() - val widget = SelectOneFromMapWidget(activityController.get(), QuestionDetails(prompt), false) + val widget = SelectOneFromMapWidget(activityController.get(), QuestionDetails(prompt), false, mock()) widget.setData(SelectOneData(choices[1].selection())) assertThat(widget.binding.answer.text, equalTo("B")) @@ -267,7 +274,7 @@ class SelectOneFromMapWidgetTest { .withSelectChoiceText(mapOf(choices[0] to "A")) .build() - val widget = SelectOneFromMapWidget(activityController.get(), QuestionDetails(prompt), false) + val widget = SelectOneFromMapWidget(activityController.get(), QuestionDetails(prompt), false, mock()) val mockValueChangedListener = mockValueChangedListener(widget) widget.setData(SelectOneData(choices[0].selection())) @@ -295,7 +302,7 @@ class SelectOneFromMapWidgetTest { .build() val widget = - SelectOneFromMapWidget(activity, QuestionDetails(prompt), false) + SelectOneFromMapWidget(activity, QuestionDetails(prompt), false, mock()) widget.setData(SelectOneData(choices[1].selection())) whenever(formEntryViewModel.getQuestionPrompt(prompt.index)).doReturn(prompt) @@ -315,13 +322,13 @@ class SelectOneFromMapWidgetTest { @Test fun `setData calls AdvanceToNextListener when the 'quick' appearance is used`() { + val listener = mock() val widget = SelectOneFromMapWidget( activityController.get(), QuestionDetails(promptWithAnswer(null)), - true + true, + listener ) - val listener = mock() - widget.autoAdvanceListener = listener val selectChoice = selectChoice(value = "a", index = 101) val answer = SelectOneData(selectChoice.selection()) @@ -331,13 +338,13 @@ class SelectOneFromMapWidgetTest { @Test fun `setData does not call AdvanceToNextListener when the 'quick' appearance is not used`() { + val listener = mock() val widget = SelectOneFromMapWidget( activityController.get(), QuestionDetails(promptWithAnswer(null)), - false + false, + listener ) - val listener = mock() - widget.autoAdvanceListener = listener val selectChoice = selectChoice(value = "a", index = 101) val answer = SelectOneData(selectChoice.selection())