Skip to content

Commit

Permalink
feat: [ANDROAPP-5893] Implement OrgUnit component (#3691)
Browse files Browse the repository at this point in the history
* Replace Org Unit with mobile ui component

* Update designSystem version to `0.3.0-SNAPSHOT`

* Fix lint error

* Fix org unit selector robot test

* Fix `shouldMoveToNextRowWhenClickingNext` test

* Fix `selectProgramStage` test

* Fix `OrgBottomSheet` clear all btn text

* Revert CellTableTest

Signed-off-by: andresmr <[email protected]>

---------

Signed-off-by: andresmr <[email protected]>
Co-authored-by: Siddharth Agarwal <[email protected]>
  • Loading branch information
andresmr and Siddharth Agarwal authored Jun 19, 2024
1 parent e7d6834 commit adfda58
Show file tree
Hide file tree
Showing 24 changed files with 43 additions and 510 deletions.
Original file line number Diff line number Diff line change
@@ -1,24 +1,16 @@
package org.dhis2.common.filters

import androidx.compose.ui.test.junit4.ComposeTestRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.performScrollTo
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.TypeTextAction
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.contrib.PickerActions
import androidx.test.espresso.contrib.RecyclerViewActions
import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.espresso.matcher.ViewMatchers.withId
import org.dhis2.R
import org.dhis2.common.BaseRobot
import org.dhis2.common.matchers.DatePickerMatchers.Companion.matchesDate
import org.dhis2.commons.filters.FilterHolder
import org.dhis2.ui.dialogs.orgunit.DONE_TEST_TAG
import org.dhis2.ui.dialogs.orgunit.ITEM_CHECK_TEST_TAG
import org.dhis2.ui.dialogs.orgunit.ITEM_TEST_TAG

fun filterRobotCommon(robotBody: FiltersRobot.() -> Unit) {
FiltersRobot().apply {
Expand Down Expand Up @@ -56,7 +48,7 @@ class FiltersRobot : BaseRobot() {
}

fun selectNotSyncedState() {
onView( withId(R.id.stateNotSynced)).perform(click())
onView(withId(R.id.stateNotSynced)).perform(click())
}

fun acceptDateSelected() {
Expand All @@ -66,6 +58,4 @@ class FiltersRobot : BaseRobot() {
fun checkDate(year: Int, monthOfYear: Int, dayOfMonth: Int) {
onView(withId(R.id.datePicker)).check(matches(matchesDate(year, monthOfYear, dayOfMonth)))
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@ package org.dhis2.usescases.orgunitselector

import androidx.compose.ui.test.junit4.ComposeTestRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.performScrollTo
import org.dhis2.common.BaseRobot
import org.dhis2.ui.dialogs.orgunit.DONE_TEST_TAG
import org.dhis2.ui.dialogs.orgunit.ITEM_CHECK_TEST_TAG

fun orgUnitSelectorRobot(
composeTestRule: ComposeTestRule,
Expand All @@ -19,9 +18,9 @@ fun orgUnitSelectorRobot(

class OrgUnitSelectorRobot(private val composeTestRule: ComposeTestRule) : BaseRobot() {
fun selectTreeOrgUnit(orgUnitName: String) {
composeTestRule.onNodeWithTag("$ITEM_CHECK_TEST_TAG$orgUnitName")
composeTestRule.onNodeWithTag("ORG_TREE_ITEM_$orgUnitName")
.performScrollTo()
.performClick()
composeTestRule.onNodeWithTag(DONE_TEST_TAG).performClick()
composeTestRule.onNodeWithText("Done").performClick()
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package org.dhis2.usescases.teidashboard.dialogs.scheduling

import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.hasTestTag
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.onAllNodesWithTag
import androidx.compose.ui.test.onFirst
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
Expand Down Expand Up @@ -110,6 +114,7 @@ class SchedulingDialogUiTest {
composeTestRule.onNodeWithText("Done").assertExists()
}

@OptIn(ExperimentalTestApi::class)
@Test
fun selectProgramStage() {
val programStages = listOf(
Expand All @@ -126,7 +131,8 @@ class SchedulingDialogUiTest {
}
}

composeTestRule.onNodeWithText("Program stage").performClick()
composeTestRule.onAllNodesWithTag("INPUT_DROPDOWN").onFirst().performClick()
composeTestRule.waitUntilExactlyOneExists(hasTestTag("INPUT_DROPDOWN_MENU_ITEM_1"))
composeTestRule.onNodeWithTag("INPUT_DROPDOWN_MENU_ITEM_1").performClick()

verify(viewModel).updateStage(programStages[1])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,6 @@ class DataSetSectionFragment : FragmentGlobalAbstract(), DataValueContract.View
updateCellValue: (TableCell) -> Unit,
) {
OUTreeFragment.Builder()
.showAsDialog()
.singleSelection()
.withPreselectedOrgUnits(cell.value?.let { listOf(it) } ?: emptyList())
.onSelection { selectedOrgUnits ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,6 @@ public void updateFilters(int totalFilters) {
@Override
public void openOrgUnitTreeSelector() {
new OUTreeFragment.Builder()
.showAsDialog()
.withPreselectedOrgUnits(FilterManager.getInstance().getOrgUnitUidsFilters())
.onSelection(selectedOrgUnits -> {
presenter.setOrgUnitFilters((List<OrganisationUnit>) selectedOrgUnits);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,6 @@ public void showOrgUnitDialog(List<OrganisationUnit> data) {
preselectedOrgUnits.add(selectedOrgUnit.uid());
}
new OUTreeFragment.Builder()
.showAsDialog()
.singleSelection()
.withPreselectedOrgUnits(preselectedOrgUnits)
.orgUnitScope(new OrgUnitSelectorScope.DataSetCaptureScope(dataSetUid))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,6 @@ class EventDetailsFragment : FragmentGlobalAbstract() {

private fun showOrgUnitDialog() {
OUTreeFragment.Builder()
.showAsDialog()
.withPreselectedOrgUnits(
viewModel.eventOrgUnit.value.selectedOrgUnit
?.let { listOf(it.uid()) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,6 @@ class ProgramFragment : FragmentGlobalAbstract(), ProgramView {

override fun openOrgUnitTreeSelector() {
OUTreeFragment.Builder()
.showAsDialog()
.withPreselectedOrgUnits(
FilterManager.getInstance().orgUnitFilters.map { it.uid() }.toMutableList(),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,6 @@ class ProgramEventDetailActivity :
override fun selectOrgUnitForNewEvent() {
enableAddEventButton(false)
OUTreeFragment.Builder()
.showAsDialog()
.singleSelection()
.orgUnitScope(
OrgUnitSelectorScope.ProgramCaptureScope(programUid),
Expand Down Expand Up @@ -373,7 +372,6 @@ class ProgramEventDetailActivity :

override fun openOrgUnitTreeSelector() {
OUTreeFragment.Builder()
.showAsDialog()
.withPreselectedOrgUnits(FilterManager.getInstance().orgUnitUidsFilters)
.onSelection { selectedOrgUnits ->
presenter.setOrgUnitFilters(selectedOrgUnits)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ class ProgramStageSelectionActivity : ActivityGlobalAbstract(), ProgramStageSele
enrollmentUid: String?,
) {
OUTreeFragment.Builder()
.showAsDialog()
.singleSelection()
.orgUnitScope(
OrgUnitSelectorScope.ProgramCaptureScope(programUid),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,6 @@ private void initSearchParameters() {
resourceManager,
(uid, preselectedOrgUnits, orgUnitScope, label) -> {
new OUTreeFragment.Builder()
.showAsDialog()
.withPreselectedOrgUnits(preselectedOrgUnits)
.singleSelection()
.onSelection(selectedOrgUnits -> {
Expand Down Expand Up @@ -649,7 +648,6 @@ public void clearFilters() {
@Override
public void openOrgUnitTreeSelector() {
new OUTreeFragment.Builder()
.showAsDialog()
.withPreselectedOrgUnits(
FilterManager.getInstance().getOrgUnitUidsFilters()
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,6 @@ public void enroll(String programUid, String uid, HashMap<String, String> queryD
allOrgUnits -> {
if (allOrgUnits.size() > 1) {
new OUTreeFragment.Builder()
.showAsDialog()
.singleSelection()
.onSelection(selectedOrgUnits -> {
if (!selectedOrgUnits.isEmpty())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,6 @@ class IndicatorsFragment : FragmentGlobalAbstract(), IndicatorsView {
lineListingColumnId: Int?,
) {
OUTreeFragment.Builder()
.showAsDialog()
.withPreselectedOrgUnits(
chartModel.graph.orgUnitsSelected(lineListingColumnId).toMutableList(),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,6 @@ class TEIDataFragment : FragmentGlobalAbstract(), TEIDataContracts.View {

override fun displayOrgUnitSelectorForNewEvent(programUid: String, programStageUid: String) {
OUTreeFragment.Builder()
.showAsDialog()
.singleSelection()
.orgUnitScope(
OrgUnitSelectorScope.ProgramCaptureScope(programUid),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,6 @@ private void handleCalendarResult(
public void enroll(String programUid, String uid) {
selectedEnrollmentDate = Calendar.getInstance().getTime();
OUTreeFragment orgUnitDialog = new OUTreeFragment.Builder()
.showAsDialog()
.singleSelection()
.onSelection(selectedOrgUnits -> {
if (!selectedOrgUnits.isEmpty())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,43 +1,34 @@
package org.dhis2.commons.orgunitselector

import android.app.Activity
import android.app.Dialog
import android.content.Context
import android.graphics.Point
import android.os.Build
import android.os.Bundle
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.fragment.app.DialogFragment
import androidx.compose.ui.res.stringResource
import androidx.fragment.app.viewModels
import com.google.accompanist.themeadapter.material3.Mdc3Theme
import org.dhis2.ui.dialogs.orgunit.OrgUnitSelectorActions
import org.dhis2.ui.dialogs.orgunit.OrgUnitSelectorDialog
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import org.dhis2.commons.R
import org.hisp.dhis.android.core.organisationunit.OrganisationUnit
import org.hisp.dhis.mobile.ui.designsystem.component.OrgBottomSheet
import javax.inject.Inject

const val ARG_SHOW_AS_DIALOG = "OUTreeFragment.ARG_SHOW_AS_DIALOG"
const val ARG_SINGLE_SELECTION = "OUTreeFragment.ARG_SINGLE_SELECTION"
const val ARG_SCOPE = "OUTreeFragment.ARG_SCOPE"
const val ARG_PRE_SELECTED_OU = "OUTreeFragment.ARG_PRE_SELECTED_OU"

class OUTreeFragment private constructor() : DialogFragment() {
class OUTreeFragment private constructor() : BottomSheetDialogFragment() {

class Builder {
private var showAsDialog = false
private var preselectedOrgUnits = listOf<String>()
private var singleSelection = false
private var selectionListener: ((selectedOrgUnits: List<OrganisationUnit>) -> Unit) = {}
private var orgUnitScope: OrgUnitSelectorScope = OrgUnitSelectorScope.UserSearchScope()
fun showAsDialog() = apply {
showAsDialog = true
}

fun withPreselectedOrgUnits(preselectedOrgUnits: List<String>) = apply {
if (singleSelection && preselectedOrgUnits.size > 1) {
Expand Down Expand Up @@ -70,7 +61,6 @@ class OUTreeFragment private constructor() : DialogFragment() {
return OUTreeFragment().apply {
selectionCallback = selectionListener
arguments = Bundle().apply {
putBoolean(ARG_SHOW_AS_DIALOG, showAsDialog)
putBoolean(ARG_SINGLE_SELECTION, singleSelection)
putParcelable(ARG_SCOPE, orgUnitScope)
putStringArrayList(ARG_PRE_SELECTED_OU, ArrayList(preselectedOrgUnits))
Expand Down Expand Up @@ -108,17 +98,9 @@ class OUTreeFragment private constructor() : DialogFragment() {
)?.inject(this)
}

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val dialog = super.onCreateDialog(savedInstanceState)
dialog.window!!.setBackgroundDrawableResource(android.R.color.transparent)
return dialog
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
showAsDialog().let { showAsDialog ->
showsDialog = showAsDialog
}
setStyle(STYLE_NORMAL, R.style.CustomBottomSheetDialogTheme)
}

override fun onCreateView(
Expand All @@ -129,41 +111,21 @@ class OUTreeFragment private constructor() : DialogFragment() {
return ComposeView(requireContext()).apply {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
Mdc3Theme {
val list by presenter.treeNodes.collectAsState()
OrgUnitSelectorDialog(
title = null,
items = list,
actions = object : OrgUnitSelectorActions {
override val onSearch: (String) -> Unit
get() = presenter::searchByName
override val onOrgUnitChecked:
(orgUnitUid: String, isChecked: Boolean) -> Unit
get() = presenter::onOrgUnitCheckChanged
override val onOpenOrgUnit: (orgUnitUid: String) -> Unit
get() = presenter::onOpenChildren
override val onDoneClick: () -> Unit
get() = this@OUTreeFragment::confirmOuSelection
override val onCancelClick: () -> Unit
get() = this@OUTreeFragment::cancelOuSelection
override val onClearClick: () -> Unit
get() = presenter::clearAll
},
)
}
val list by presenter.treeNodes.collectAsState()
OrgBottomSheet(
clearAllButtonText = stringResource(id = R.string.action_clear_all),
orgTreeItems = list,
onSearch = presenter::searchByName,
onDismiss = { cancelOuSelection() },
onItemClick = presenter::onOpenChildren,
onItemSelected = presenter::onOrgUnitCheckChanged,
onClearAll = presenter::clearAll,
onDone = { confirmOuSelection() },
)
}
}
}

override fun onResume() {
super.onResume()
showAsDialog().takeIf { it }?.let {
fixDialogSize(0.9, 0.9)
}
}

private fun showAsDialog() = arguments?.getBoolean(ARG_SHOW_AS_DIALOG, false) ?: false

private fun confirmOuSelection() {
selectionCallback(presenter.getOrgUnits())
exitOuSelection()
Expand All @@ -175,25 +137,6 @@ class OUTreeFragment private constructor() : DialogFragment() {
}

private fun exitOuSelection() {
if (showAsDialog()) {
dismiss()
} else {
activity?.apply {
setResult(Activity.RESULT_OK)
finish()
}
}
}
}

fun DialogFragment.fixDialogSize(widthPercent: Double, heightPercent: Double) {
val size = Point()
dialog?.window?.apply {
windowManager.defaultDisplay.getSize(size)

setLayout(widthPercent of size.x, heightPercent of size.y)
setGravity(Gravity.CENTER)
dismiss()
}
}

private infix fun Double.of(value: Int) = (this * value).toInt()
Loading

0 comments on commit adfda58

Please sign in to comment.