Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
d0e5709
Move geopoly UI code to Fragment
seadowg Dec 2, 2025
9fa9189
Remove unused title from geotrace view
seadowg Dec 2, 2025
9a0f518
Extract super class for widget answer dialogs
seadowg Dec 3, 2025
ac334ab
Move WidgetAnswerDialogFragment to its own file
seadowg Dec 3, 2025
724ebcd
Fix references in tests
seadowg Dec 3, 2025
bac1082
Convert intent to constructor params
seadowg Dec 4, 2025
c0f12a1
Add GeoPolyDialogFragment that handles read only and output mode
seadowg Dec 4, 2025
fffe330
Generalize test helper
seadowg Dec 5, 2025
c2c1dfb
Add allow-mock-accuracy support to GeoPolyDialogFragment
seadowg Dec 8, 2025
969e160
Add existing answer support to GeoPolyDialogFragment
seadowg Dec 8, 2025
1af0f0a
Fix OutputMode matching
seadowg Dec 8, 2025
eb56037
Add result handling to GeoPolyDialogFragment
seadowg Dec 8, 2025
10b47a4
Spike out using Fragment instead of Activity for geotrace
seadowg Dec 8, 2025
f55d1d9
Fix tests
seadowg Dec 9, 2025
a9a183b
Remove external Activity integration points for geotrace
seadowg Dec 9, 2025
1f1e00b
Rework requestGeoTrace to work for both geopoly types
seadowg Dec 9, 2025
96a9bcc
Use dialog for geoshape as well
seadowg Dec 9, 2025
dddfb56
Remove external Activity integration points for geoshape
seadowg Dec 9, 2025
9314603
Remove GeoPolyActivity
seadowg Dec 9, 2025
f240b47
Fix Fragment recreation bug
seadowg Dec 9, 2025
2a59105
Pull out MockFragmentFactory
seadowg Dec 9, 2025
88c3947
Add assertDisabled
seadowg Dec 11, 2025
e2ad4de
Make language for constants consistent
seadowg Dec 11, 2025
37f8a7a
Correct typo
seadowg Dec 11, 2025
ecfbed3
Move helper to test helpers
seadowg Dec 11, 2025
98cc919
Simplify inputPolygon
seadowg Dec 11, 2025
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
Prev Previous commit
Next Next commit
Move WidgetAnswerDialogFragment to its own file
  • Loading branch information
seadowg committed Dec 9, 2025
commit ac334ab62ef8f41b1ac60f356af6d3009955f60d
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,19 @@ package org.odk.collect.android.widgets.items

import android.content.Context
import android.content.res.Resources
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.activity.ComponentDialog
import androidx.appcompat.widget.Toolbar
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.fragment.app.commit
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModelProvider
import org.javarosa.core.model.FormIndex
import org.javarosa.core.model.SelectChoice
import org.javarosa.core.model.data.IAnswerData
import org.javarosa.core.model.data.SelectOneData
import org.javarosa.form.api.FormEntryPrompt
import org.odk.collect.android.R
import org.odk.collect.android.databinding.WidgetAnswerDialogLayoutBinding
import org.odk.collect.android.formentry.FormEntryViewModel
import org.odk.collect.android.injection.DaggerUtils
import org.odk.collect.android.utilities.Appearances
import org.odk.collect.android.widgets.utilities.GeoWidgetUtils
import org.odk.collect.android.widgets.utilities.WidgetAnswerDialogFragment
import org.odk.collect.androidshared.livedata.MutableNonNullLiveData
import org.odk.collect.androidshared.livedata.NonNullLiveData
import org.odk.collect.androidshared.ui.FragmentFactoryBuilder
import org.odk.collect.async.Scheduler
import org.odk.collect.entities.javarosa.parse.EntitySchema
import org.odk.collect.geo.geopoly.GeoPolyUtils.parseGeometry
Expand All @@ -36,9 +23,7 @@ import org.odk.collect.geo.selection.MappableSelectItem
import org.odk.collect.geo.selection.SelectionMapData
import org.odk.collect.geo.selection.SelectionMapFragment
import org.odk.collect.geo.selection.SelectionMapFragment.Companion.REQUEST_SELECT_ITEM
import org.odk.collect.material.MaterialFullScreenDialogFragment
import javax.inject.Inject
import kotlin.reflect.KClass

class SelectOneFromMapDialogFragment(viewModelFactory: ViewModelProvider.Factory) :
WidgetAnswerDialogFragment<SelectionMapFragment>(
Expand Down Expand Up @@ -76,66 +61,6 @@ class SelectOneFromMapDialogFragment(viewModelFactory: ViewModelProvider.Factory
}
}

abstract class WidgetAnswerDialogFragment<T : Fragment>(
private val type: KClass<T>,
private val viewModelFactory: ViewModelProvider.Factory
) : MaterialFullScreenDialogFragment() {

private val formEntryViewModel: FormEntryViewModel by activityViewModels { viewModelFactory }
private val prompt: FormEntryPrompt by lazy {
formEntryViewModel.getQuestionPrompt(requireArguments().getSerializable(ARG_FORM_INDEX) as FormIndex)
}

abstract fun onCreateFragment(prompt: FormEntryPrompt): T

override fun onAttach(context: Context) {
super.onAttach(context)

childFragmentManager.fragmentFactory = FragmentFactoryBuilder()
.forClass(type) { onCreateFragment(prompt) }
.build()
}

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val binding = WidgetAnswerDialogLayoutBinding.inflate(inflater)
return binding.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
childFragmentManager.commit {
add(R.id.answer_fragment, type.java, null)
}
}

override fun getToolbar(): Toolbar? {
return null
}

override fun onBackPressed() {
dismiss()
}

override fun onCloseClicked() {
// No toolbar so not relevant
}

fun onAnswer(answer: IAnswerData, dismiss: Boolean = true) {
formEntryViewModel.answerQuestion(prompt.index, answer)

if (dismiss) {
dismiss()
}
}

companion object {
const val ARG_FORM_INDEX = "form_index"
}
}

internal class SelectChoicesMapData(
private val resources: Resources,
scheduler: Scheduler,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import org.odk.collect.android.databinding.SelectOneFromMapWidgetAnswerBinding
import org.odk.collect.android.formentry.questions.QuestionDetails
import org.odk.collect.android.widgets.QuestionWidget
import org.odk.collect.android.widgets.items.SelectOneFromMapDialogFragment.Companion.ARG_SELECTED_INDEX
import org.odk.collect.android.widgets.items.WidgetAnswerDialogFragment.Companion.ARG_FORM_INDEX
import org.odk.collect.android.widgets.utilities.WidgetAnswerDialogFragment.Companion.ARG_FORM_INDEX
import org.odk.collect.androidshared.ui.DialogFragmentUtils
import org.odk.collect.permissions.PermissionListener

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package org.odk.collect.android.widgets.utilities

import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.widget.Toolbar
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.fragment.app.commit
import androidx.lifecycle.ViewModelProvider
import org.javarosa.core.model.FormIndex
import org.javarosa.core.model.data.IAnswerData
import org.javarosa.form.api.FormEntryPrompt
import org.odk.collect.android.R
import org.odk.collect.android.databinding.WidgetAnswerDialogLayoutBinding
import org.odk.collect.android.formentry.FormEntryViewModel
import org.odk.collect.androidshared.ui.FragmentFactoryBuilder
import org.odk.collect.material.MaterialFullScreenDialogFragment
import kotlin.reflect.KClass

abstract class WidgetAnswerDialogFragment<T : Fragment>(
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I imagine pretty soon we'll want this to be more general so that the "child" view doesn't have to be a Fragment (and allow Composables etc). I thought it'd be better to wait for that to be needed than try and anticipate the ideal structure now though.

private val type: KClass<T>,
private val viewModelFactory: ViewModelProvider.Factory
) : MaterialFullScreenDialogFragment() {

private val formEntryViewModel: FormEntryViewModel by activityViewModels { viewModelFactory }
private val prompt: FormEntryPrompt by lazy {
formEntryViewModel.getQuestionPrompt(requireArguments().getSerializable(ARG_FORM_INDEX) as FormIndex)
}

abstract fun onCreateFragment(prompt: FormEntryPrompt): T

override fun onAttach(context: Context) {
super.onAttach(context)

childFragmentManager.fragmentFactory = FragmentFactoryBuilder()
.forClass(type) { onCreateFragment(prompt) }
.build()
}

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val binding = WidgetAnswerDialogLayoutBinding.inflate(inflater)
return binding.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
childFragmentManager.commit {
add(R.id.answer_fragment, type.java, null)
}
}

override fun getToolbar(): Toolbar? {
return null
}

override fun onBackPressed() {
dismiss()
}

override fun onCloseClicked() {
// No toolbar so not relevant
}

fun onAnswer(answer: IAnswerData, dismiss: Boolean = true) {
formEntryViewModel.answerQuestion(prompt.index, answer)

if (dismiss) {
dismiss()
}
}

companion object {
const val ARG_FORM_INDEX = "form_index"
}
}