Skip to content

Commit

Permalink
add component
Browse files Browse the repository at this point in the history
  • Loading branch information
Siddharth Agarwal committed Oct 6, 2023
1 parent 56580e0 commit e013521
Show file tree
Hide file tree
Showing 6 changed files with 373 additions and 0 deletions.
2 changes: 2 additions & 0 deletions common/src/commonMain/kotlin/org/hisp/dhis/common/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import org.hisp.dhis.common.screens.InputLongTextScreen
import org.hisp.dhis.common.screens.InputMatrixScreen
import org.hisp.dhis.common.screens.InputNegativeIntegerScreen
import org.hisp.dhis.common.screens.InputNumberScreen
import org.hisp.dhis.common.screens.InputOrgUnitScreen
import org.hisp.dhis.common.screens.InputPercentageScreen
import org.hisp.dhis.common.screens.InputPhoneNumberScreen
import org.hisp.dhis.common.screens.InputPositiveIntegerOrZeroScreen
Expand Down Expand Up @@ -167,6 +168,7 @@ fun Main() {
Components.INPUT_PHONE_NUMBER -> InputPhoneNumberScreen()
Components.INPUT_LINK -> InputLinkScreen()
Components.INPUT_EMAIL -> InputEmailScreen()
Components.INPUT_ORG_UNIT -> InputOrgUnitScreen()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,5 @@ enum class Components(val label: String) {
INPUT_PHONE_NUMBER("Input Phone Number"),
INPUT_LINK("Input Link"),
INPUT_EMAIL("Input Email"),
INPUT_ORG_UNIT("Input Org. Unit"),
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package org.hisp.dhis.common.screens

import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import org.hisp.dhis.mobile.ui.designsystem.component.ColumnComponentContainer
import org.hisp.dhis.mobile.ui.designsystem.component.InputOrgUnit
import org.hisp.dhis.mobile.ui.designsystem.component.InputShellState
import org.hisp.dhis.mobile.ui.designsystem.component.SubTitle
import org.hisp.dhis.mobile.ui.designsystem.component.SupportingTextData
import org.hisp.dhis.mobile.ui.designsystem.component.SupportingTextState
import org.hisp.dhis.mobile.ui.designsystem.component.Title
import org.hisp.dhis.mobile.ui.designsystem.theme.Spacing
import org.hisp.dhis.mobile.ui.designsystem.theme.TextColor

@Composable
fun InputOrgUnitScreen() {
ColumnComponentContainer {
Title("Input Org. unit component", textColor = TextColor.OnSurfaceVariant)
SubTitle("Basic Org. unit ", textColor = TextColor.OnSurfaceVariant)
var inputText1 by rememberSaveable { mutableStateOf("") }

InputOrgUnit(
title = "Label",
inputText = inputText1,
onValueChanged = {
if (it != null) {
inputText1 = it
}
},
onOrgUnitActionCLicked = {},
)
Spacer(Modifier.size(Spacing.Spacing18))

SubTitle("Basic Org. unit with content ", textColor = TextColor.OnSurfaceVariant)
var inputText2 by rememberSaveable { mutableStateOf("PHC Fakename") }

InputOrgUnit(
title = "Label",
inputText = inputText2,
onValueChanged = {
if (it != null) {
inputText2 = it
}
},
onOrgUnitActionCLicked = {},
)
Spacer(Modifier.size(Spacing.Spacing18))

SubTitle("Error Org. unit required field ", textColor = TextColor.OnSurfaceVariant)
var inputText3 by rememberSaveable { mutableStateOf("") }

InputOrgUnit(
title = "Label",
state = InputShellState.ERROR,
supportingText = listOf(SupportingTextData("Required", SupportingTextState.ERROR)),
inputText = inputText3,
isRequiredField = true,
onValueChanged = {
if (it != null) {
inputText3 = it
}
},
onOrgUnitActionCLicked = {},
)
Spacer(Modifier.size(Spacing.Spacing18))

SubTitle("Disabled Org. unit with content ", textColor = TextColor.OnSurfaceVariant)
var inputText5 by rememberSaveable { mutableStateOf("PHC Fakename") }
InputOrgUnit(
title = "Label",
state = InputShellState.DISABLED,
inputText = inputText5,
onValueChanged = {
if (it != null) {
inputText5 = it
}
},
onOrgUnitActionCLicked = {},
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package org.hisp.dhis.mobile.ui.designsystem.component

import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.Icon
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.text.input.ImeAction
import org.hisp.dhis.mobile.ui.designsystem.resource.provideDHIS2Icon

/**
* DHIS2 Input org unit. Wraps DHIS · [BasicTextInput].
* @param title controls the text to be shown for the title
* @param state Manages the InputShell state
* @param supportingText is a list of SupportingTextData that
* manages all the messages to be shown
* @param legendData manages the legendComponent
* @param inputText manages the value of the text in the input field
* @param isRequiredField controls whether the field is mandatory or not
* @param onNextClicked gives access to the imeAction event
* @param onValueChanged gives access to the onValueChanged event
* @param onFocusChanged gives access to the onFocusChanged returns true if
* item is focused
* @param imeAction controls the imeAction button to be shown
* @param modifier allows a modifier to be passed externally
* @param onOrgUnitActionCLicked callback to when org unit button is clicked
*/
@Composable
fun InputOrgUnit(
title: String,
state: InputShellState = InputShellState.UNFOCUSED,
supportingText: List<SupportingTextData>? = null,
legendData: LegendData? = null,
inputText: String? = null,
isRequiredField: Boolean = false,
onNextClicked: (() -> Unit)? = null,
onValueChanged: ((String?) -> Unit)? = null,
onFocusChanged: ((Boolean) -> Unit)? = null,
imeAction: ImeAction = ImeAction.Next,
modifier: Modifier = Modifier,
onOrgUnitActionCLicked: () -> Unit,
) {
BasicTextInput(
title = title,
state = state,
supportingText = supportingText,
legendData = legendData,
inputText = inputText,
isRequiredField = isRequiredField,
onNextClicked = onNextClicked,
onValueChanged = onValueChanged,
keyboardOptions = KeyboardOptions(imeAction = imeAction),
modifier = modifier,
testTag = "ORG_UNIT",
onFocusChanged = onFocusChanged,
actionButton = {
SquareIconButton(
modifier = Modifier.testTag("ORG_UNIT_BUTTON"),
enabled = state != InputShellState.DISABLED,
icon = {
Icon(
painter = provideDHIS2Icon("org_unit"),
contentDescription = "org_unit_icon",
)
},
onClick = onOrgUnitActionCLicked,
)
},
)
}
10 changes: 10 additions & 0 deletions designsystem/src/commonMain/resources/drawable/org_unit.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M3,4V6.352H4.994V4H3ZM12.545,6.207V11.125H14.957C14.977,11.125 14.995,11.131 15.016,11.131C15.036,11.131 15.054,11.125 15.074,11.125H17.463V8.756C17.464,8.729 17.471,8.703 17.471,8.676C17.471,8.648 17.464,8.623 17.463,8.596V6.207H12.545ZM3,7.5V9.852H4.994V7.5H3ZM6.213,7.678V9.672H8.564V7.678H6.213ZM9.713,7.678V9.672H12.064V7.678H9.713ZM3,10.998V13.352H4.994V10.998H3ZM3,14.498V16.852H3.01C3.008,16.887 3,16.918 3,16.953C3,18.313 4.095,19.41 5.455,19.41C5.49,19.41 5.524,19.4 5.559,19.398V19.41H7.91V17.418H7.865H5.559H5.455H5.434V17.414C5.193,17.403 5.003,17.211 4.996,16.969H4.994V16.953V14.543V14.498H3ZM15.398,15.949V20.867H17.861H20.316V18.414V15.949H15.398ZM9.059,17.418V19.41H11.41V17.418H9.059ZM12.559,17.418V19.41H14.91V17.418H12.559Z"
android:fillColor="#000000"
android:fillType="evenOdd"/>
</vector>
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
package org.hisp.dhis.mobile.ui.designsystem.component

import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.test.assert
import androidx.compose.ui.test.assertHasClickAction
import androidx.compose.ui.test.assertIsEnabled
import androidx.compose.ui.test.assertIsNotEnabled
import androidx.compose.ui.test.assertTextEquals
import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.performTextInput
import org.hisp.dhis.mobile.ui.designsystem.theme.SurfaceColor
import org.junit.Rule
import org.junit.Test

class InputOrgUnitTest {
@get:Rule
val rule = createComposeRule()

@Test
fun shouldDisplayInputOrgUnitCorrectly() {
rule.setContent {
InputOrgUnit(
title = "Label",
onOrgUnitActionCLicked = {},
)
}
rule.onNodeWithTag("INPUT_ORG_UNIT").assertExists()
rule.onNodeWithTag("INPUT_ORG_UNIT_LEGEND").assertDoesNotExist()
rule.onNodeWithTag("INPUT_ORG_UNIT_SUPPORTING_TEXT").assertDoesNotExist()
}

@Test
fun shouldAllowUserInputWhenEnabled() {
rule.setContent {
var inputValue by rememberSaveable { mutableStateOf("") }
InputOrgUnit(
title = "Label",
inputText = inputValue,
onValueChanged = {
if (it != null) {
inputValue = it
}
},
onOrgUnitActionCLicked = {},
)
}
rule.onNodeWithTag("INPUT_ORG_UNIT").assertExists()
rule.onNodeWithTag("INPUT_ORG_UNIT_FIELD").performTextInput("PHC fake")
rule.onNodeWithTag("INPUT_ORG_UNIT_FIELD").assert(hasText("PHC fake"))
}

@Test
fun shouldNotAllowUserInputWhenDisabled() {
rule.setContent {
InputOrgUnit(
title = "Label",
state = InputShellState.DISABLED,
onOrgUnitActionCLicked = {},
)
}
rule.onNodeWithTag("INPUT_ORG_UNIT").assertExists()
rule.onNodeWithTag("INPUT_ORG_UNIT_FIELD").assertIsNotEnabled()
}

@Test
fun shouldShowResetButtonWhenTextFieldHasContent() {
rule.setContent {
var inputValue by rememberSaveable { mutableStateOf("") }
InputOrgUnit(
title = "Label",
inputText = inputValue,
onValueChanged = {
if (it != null) {
inputValue = it
}
},
onOrgUnitActionCLicked = {},
)
}
rule.onNodeWithTag("INPUT_ORG_UNIT").assertExists()
rule.onNodeWithTag("INPUT_ORG_UNIT_FIELD").assertExists()
rule.onNodeWithTag("INPUT_ORG_UNIT_FIELD").performTextInput("PHC fake")
rule.onNodeWithTag("INPUT_ORG_UNIT_RESET_BUTTON").assertExists()
}

@Test
fun shouldDeleteContentWhenResetButtonIsClickedAndHideResetButton() {
rule.setContent {
var inputValue by rememberSaveable { mutableStateOf("PHC fake") }

InputOrgUnit(
title = "Label",
inputText = inputValue,
onValueChanged = {
if (it != null) {
inputValue = it
}
},
onOrgUnitActionCLicked = {},
)
}
rule.onNodeWithTag("INPUT_ORG_UNIT").assertExists()
rule.onNodeWithTag("INPUT_ORG_UNIT_RESET_BUTTON").assertExists()
rule.onNodeWithTag("INPUT_ORG_UNIT_RESET_BUTTON").performClick()
rule.onNodeWithTag("INPUT_ORG_UNIT_FIELD").assertTextEquals("")
rule.onNodeWithTag("INPUT_ORG_UNIT_RESET_BUTTON").assertDoesNotExist()
}

@Test
fun shouldHideResetButtonWhenDisabled() {
rule.setContent {
var inputValue by rememberSaveable { mutableStateOf("PHC fake") }
InputOrgUnit(
title = "Label",
state = InputShellState.DISABLED,
inputText = inputValue,
onValueChanged = {
if (it != null) {
inputValue = it
}
},
onOrgUnitActionCLicked = {},
)
}
rule.onNodeWithTag("INPUT_ORG_UNIT").assertExists()
rule.onNodeWithTag("INPUT_ORG_UNIT_RESET_BUTTON").assertDoesNotExist()
}

@Test
fun shouldShowLegendCorrectly() {
rule.setContent {
InputOrgUnit(
title = "Label",
inputText = "Input",
legendData = LegendData(SurfaceColor.CustomGreen, "Legend"),
onOrgUnitActionCLicked = {},
)
}
rule.onNodeWithTag("INPUT_ORG_UNIT").assertExists()
rule.onNodeWithTag("INPUT_ORG_UNIT_LEGEND").assertExists()
rule.onNodeWithTag("INPUT_ORG_UNIT_LEGEND").assertHasClickAction()
}

@Test
fun shouldShowSupportingTextCorrectly() {
rule.setContent {
InputOrgUnit(
title = "Label",
inputText = "Input",
supportingText = listOf(SupportingTextData("Supporting text", SupportingTextState.DEFAULT)),
onOrgUnitActionCLicked = {},
)
}
rule.onNodeWithTag("INPUT_ORG_UNIT").assertExists()
rule.onNodeWithTag("INPUT_ORG_UNIT_SUPPORTING_TEXT").assertExists()
}

@Test
fun shouldEnableOrgUnitActionButtonWhenEnabled() {
rule.setContent {
var inputValue by remember { mutableStateOf("") }

InputOrgUnit(
title = "Label",
inputText = inputValue,
onValueChanged = {
if (it != null) {
inputValue = it
}
},
onOrgUnitActionCLicked = {},
)
}
rule.onNodeWithTag("ORG_UNIT_BUTTON").assertIsEnabled()
}

@Test
fun shouldDisableOrgUnitActionButtonOnWhenDisabled() {
rule.setContent {
var inputValue by remember { mutableStateOf("PHC fake") }

InputOrgUnit(
title = "Label",
state = InputShellState.DISABLED,
inputText = inputValue,
onValueChanged = {
if (it != null) {
inputValue = it
}
},
onOrgUnitActionCLicked = {},
)
}
rule.onNodeWithTag("ORG_UNIT_BUTTON").assertIsNotEnabled()
}
}

0 comments on commit e013521

Please sign in to comment.