From 61e1b58883b40cda30955902d3d8e175711f2b27 Mon Sep 17 00:00:00 2001 From: Siddharth Agarwal Date: Fri, 6 Oct 2023 16:48:06 +0530 Subject: [PATCH 1/4] ANDROAPP-5572-mobile-ui-Create-InputOrgUnit-component Co-authored-by: Siddharth Agarwal --- .../kotlin/org/hisp/dhis/common/App.kt | 2 + .../hisp/dhis/common/screens/Components.kt | 1 + .../dhis/common/screens/InputOrgUnitScreen.kt | 87 ++++++++ .../ui/designsystem/component/InputOrgUnit.kt | 70 ++++++ .../resources/drawable/org_unit.xml | 10 + .../component/InputOrgUnitTest.kt | 203 ++++++++++++++++++ 6 files changed, 373 insertions(+) create mode 100644 common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputOrgUnitScreen.kt create mode 100644 designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputOrgUnit.kt create mode 100644 designsystem/src/commonMain/resources/drawable/org_unit.xml create mode 100644 designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputOrgUnitTest.kt diff --git a/common/src/commonMain/kotlin/org/hisp/dhis/common/App.kt b/common/src/commonMain/kotlin/org/hisp/dhis/common/App.kt index 11790b1af..87c20f516 100644 --- a/common/src/commonMain/kotlin/org/hisp/dhis/common/App.kt +++ b/common/src/commonMain/kotlin/org/hisp/dhis/common/App.kt @@ -44,6 +44,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 @@ -169,6 +170,7 @@ fun Main() { Components.INPUT_LINK -> InputLinkScreen() Components.INPUT_EMAIL -> InputEmailScreen() Components.CAROUSEL_BUTTONS -> ButtonCarouselScreen() + Components.INPUT_ORG_UNIT -> InputOrgUnitScreen() } } } diff --git a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/Components.kt b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/Components.kt index f93e3310c..7ef94940b 100644 --- a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/Components.kt +++ b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/Components.kt @@ -45,4 +45,5 @@ enum class Components(val label: String) { INPUT_LINK("Input Link"), INPUT_EMAIL("Input Email"), CAROUSEL_BUTTONS("Carousel buttons"), + INPUT_ORG_UNIT("Input Org. Unit"), } diff --git a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputOrgUnitScreen.kt b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputOrgUnitScreen.kt new file mode 100644 index 000000000..301d17584 --- /dev/null +++ b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputOrgUnitScreen.kt @@ -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 = {}, + ) + } +} diff --git a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputOrgUnit.kt b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputOrgUnit.kt new file mode 100644 index 000000000..29e211bcf --- /dev/null +++ b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputOrgUnit.kt @@ -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? = 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, + ) + }, + ) +} diff --git a/designsystem/src/commonMain/resources/drawable/org_unit.xml b/designsystem/src/commonMain/resources/drawable/org_unit.xml new file mode 100644 index 000000000..a9a2ae176 --- /dev/null +++ b/designsystem/src/commonMain/resources/drawable/org_unit.xml @@ -0,0 +1,10 @@ + + + diff --git a/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputOrgUnitTest.kt b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputOrgUnitTest.kt new file mode 100644 index 000000000..eafc4aca5 --- /dev/null +++ b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputOrgUnitTest.kt @@ -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() + } +} From 0ac0ac2aad48f2672404f00a05db67ca2f2c3ce4 Mon Sep 17 00:00:00 2001 From: manu Date: Fri, 6 Oct 2023 12:36:30 +0200 Subject: [PATCH 2/4] add light text button style --- .../hisp/dhis/mobile/ui/designsystem/component/Button.kt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/Button.kt b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/Button.kt index e66448630..135144953 100644 --- a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/Button.kt +++ b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/Button.kt @@ -83,8 +83,12 @@ fun Button( paddingValues = paddingValues, ) } - ButtonStyle.TEXT -> { - val textColor = if (enabled) SurfaceColor.Primary else TextColor.OnDisabledSurface + ButtonStyle.TEXT, ButtonStyle.TEXT_LIGHT -> { + val textColor = when { + !enabled -> TextColor.OnDisabledSurface + style == ButtonStyle.TEXT_LIGHT -> TextColor.OnPrimary + else -> SurfaceColor.Primary + } CompositionLocalProvider(LocalRippleTheme provides Ripple.CustomDHISRippleTheme) { OutlinedButton( modifier = modifier, @@ -311,6 +315,7 @@ enum class ButtonStyle { FILLED, OUTLINED, TEXT, + TEXT_LIGHT, ELEVATED, TONAL, KEYBOARDKEY, From b32d251e3d4f3c8d90726d2eb149a3d8bf911eab Mon Sep 17 00:00:00 2001 From: Xavier Molloy <44061143+xavimolloy@users.noreply.github.com> Date: Sat, 7 Oct 2023 09:28:58 +0200 Subject: [PATCH 3/4] ANDROAPP-5613-Make state not nullable (#92) * add supporting text as input phone number param, make state not nullable for input shell and basic text input * make state not nullable for input components * fix test --- .../dhis/common/screens/FormShellsScreen.kt | 10 +++++++++- .../dhis/common/screens/InputCheckBoxScreen.kt | 2 ++ .../dhis/common/screens/InputEmailScreen.kt | 2 ++ .../dhis/common/screens/InputIntegerScreen.kt | 1 + .../dhis/common/screens/InputLetterScreen.kt | 1 + .../hisp/dhis/common/screens/InputLinkScreen.kt | 3 +++ .../dhis/common/screens/InputLongTextScreen.kt | 1 + .../dhis/common/screens/InputMatrixScreen.kt | 1 + .../screens/InputNegativeIntegerScreen.kt | 1 + .../dhis/common/screens/InputNumberScreen.kt | 2 ++ .../common/screens/InputPercentageScreen.kt | 1 + .../common/screens/InputPhoneNumberScreen.kt | 1 + .../screens/InputPositiveIntegerOrZeroScreen.kt | 1 + .../screens/InputPositiveIntegerScreen.kt | 1 + .../common/screens/InputRadioButtonScreen.kt | 2 ++ .../common/screens/InputSequentialScreen.kt | 1 + .../hisp/dhis/common/screens/InputTextScreen.kt | 1 + .../common/screens/InputYesNoFieldScreen.kt | 2 ++ .../screens/InputYesOnlyCheckBoxScreen.kt | 6 ++++-- .../common/screens/InputYesOnlySwitchScreen.kt | 2 ++ .../hisp/dhis/common/screens/SectionScreen.kt | 4 ++++ .../ui/designsystem/component/BasicTextInput.kt | 2 +- .../ui/designsystem/component/InputCheckBox.kt | 2 +- .../ui/designsystem/component/InputEmail.kt | 2 +- .../ui/designsystem/component/InputInteger.kt | 2 +- .../ui/designsystem/component/InputLetter.kt | 2 +- .../ui/designsystem/component/InputLink.kt | 2 +- .../ui/designsystem/component/InputLongText.kt | 2 +- .../ui/designsystem/component/InputMatrix.kt | 3 +-- .../component/InputNegativeInteger.kt | 2 +- .../ui/designsystem/component/InputNumber.kt | 2 +- .../designsystem/component/InputPercentage.kt | 2 +- .../designsystem/component/InputPhoneNumber.kt | 17 ++--------------- .../component/InputPositiveInteger.kt | 2 +- .../component/InputPositiveIntegerOrZero.kt | 2 +- .../ui/designsystem/component/InputQRCode.kt | 7 +++++-- .../designsystem/component/InputRadioButton.kt | 3 +-- .../designsystem/component/InputSequential.kt | 3 +-- .../ui/designsystem/component/InputShell.kt | 2 +- .../ui/designsystem/component/InputText.kt | 2 +- .../designsystem/component/InputYesNoField.kt | 2 +- .../component/InputYesOnlyCheckBox.kt | 2 +- .../component/InputYesOnlySwitch.kt | 2 +- .../designsystem/component/InputCheckBoxTest.kt | 7 +++++++ .../ui/designsystem/component/InputEmailTest.kt | 8 ++++++++ .../designsystem/component/InputIntegerTest.kt | 9 +++++++++ .../designsystem/component/InputLetterTest.kt | 7 +++++++ .../ui/designsystem/component/InputLinkTest.kt | 8 ++++++++ .../designsystem/component/InputLongTextTest.kt | 6 ++++++ .../component/InputNegativeIntegerTest.kt | 8 ++++++++ .../designsystem/component/InputNumberTest.kt | 7 +++++++ .../component/InputPercentageTest.kt | 8 ++++++++ .../component/InputPhoneNumberTest.kt | 5 ++++- .../component/InputPositiveIntegerOrZeroTest.kt | 10 ++++++++++ .../component/InputPositiveIntegerTest.kt | 9 +++++++++ .../designsystem/component/InputQRCodeTest.kt | 3 +++ .../component/InputRadioButtonTest.kt | 7 +++++++ .../ui/designsystem/component/InputTextTest.kt | 6 ++++++ .../component/InputYesNoFieldTest.kt | 7 +++++++ .../component/InputYesOnlyCheckBoxTest.kt | 6 +++++- .../component/InputYesOnlySwitchTest.kt | 4 ++++ 61 files changed, 193 insertions(+), 45 deletions(-) diff --git a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/FormShellsScreen.kt b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/FormShellsScreen.kt index 17fcd8f41..bd3cdb9f8 100644 --- a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/FormShellsScreen.kt +++ b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/FormShellsScreen.kt @@ -38,6 +38,7 @@ fun FormShellsScreen() { inputValue1 = it } }, + state = InputShellState.UNFOCUSED, ) Spacer(Modifier.size(Spacing.Spacing18)) @@ -52,7 +53,7 @@ fun FormShellsScreen() { inputValue2 = it } }, - + state = InputShellState.UNFOCUSED, ) Spacer(Modifier.size(Spacing.Spacing18)) @@ -124,6 +125,7 @@ fun FormShellsScreen() { inputValue7 = it } }, + state = InputShellState.ERROR, ) Spacer(Modifier.size(Spacing.Spacing18)) @@ -159,6 +161,7 @@ fun FormShellsScreen() { inputValue9 = it } }, + state = InputShellState.UNFOCUSED, ) Spacer(Modifier.size(Spacing.Spacing18)) @@ -178,6 +181,8 @@ fun FormShellsScreen() { inputValue10 = it } }, + state = InputShellState.UNFOCUSED, + ) Spacer(Modifier.size(Spacing.Spacing18)) @@ -263,6 +268,7 @@ fun FormShellsScreen() { inputValue14 = it } }, + state = InputShellState.UNFOCUSED, ) var inputValue15 by rememberSaveable { mutableStateOf("Input") } @@ -275,6 +281,7 @@ fun FormShellsScreen() { inputValue15 = it } }, + state = InputShellState.UNFOCUSED, ) Spacer(Modifier.size(Spacing.Spacing18)) @@ -296,6 +303,7 @@ fun FormShellsScreen() { inputValue16 = it } }, + state = InputShellState.UNFOCUSED, ) } } diff --git a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputCheckBoxScreen.kt b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputCheckBoxScreen.kt index ec81816af..38a960616 100644 --- a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputCheckBoxScreen.kt +++ b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputCheckBoxScreen.kt @@ -68,6 +68,7 @@ fun InputCheckBoxScreen() { checkBoxDataItemsVertical[index] = checkBoxData.copy(checked = !checkBoxData.checked) }, onClearSelection = { checkBoxDataItemsVertical.replaceAll { it.copy(checked = false) } }, + state = InputShellState.UNFOCUSED, ) Spacer(Modifier.size(Spacing.Spacing18)) InputCheckBox( @@ -99,6 +100,7 @@ fun InputCheckBoxScreen() { checkBoxDataItemsHorizontal[index] = checkBoxData.copy(checked = !checkBoxData.checked) }, onClearSelection = { checkBoxDataItemsHorizontal.replaceAll { it.copy(checked = false) } }, + state = InputShellState.UNFOCUSED, ) } } diff --git a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputEmailScreen.kt b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputEmailScreen.kt index d42b8b2d8..901da6625 100644 --- a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputEmailScreen.kt +++ b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputEmailScreen.kt @@ -35,6 +35,7 @@ fun InputEmailScreen() { } }, onEmailActionCLicked = {}, + state = InputShellState.UNFOCUSED, ) Spacer(Modifier.size(Spacing.Spacing18)) @@ -51,6 +52,7 @@ fun InputEmailScreen() { } }, onEmailActionCLicked = {}, + state = InputShellState.UNFOCUSED, ) Spacer(Modifier.size(Spacing.Spacing18)) diff --git a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputIntegerScreen.kt b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputIntegerScreen.kt index 66e35c69d..17fab4e97 100644 --- a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputIntegerScreen.kt +++ b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputIntegerScreen.kt @@ -33,6 +33,7 @@ fun InputIntegerScreen() { inputValue1 = it } }, + state = InputShellState.UNFOCUSED, ) Spacer(Modifier.size(Spacing.Spacing18)) diff --git a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputLetterScreen.kt b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputLetterScreen.kt index 9b4feabe8..2fd6a7431 100644 --- a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputLetterScreen.kt +++ b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputLetterScreen.kt @@ -33,6 +33,7 @@ fun InputLetterScreen() { inputValue1 = it } }, + state = InputShellState.UNFOCUSED, ) Spacer(Modifier.size(Spacing.Spacing18)) diff --git a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputLinkScreen.kt b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputLinkScreen.kt index 158779c7a..cf6976962 100644 --- a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputLinkScreen.kt +++ b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputLinkScreen.kt @@ -35,6 +35,7 @@ fun InputLinkScreen() { } }, onLinkActionCLicked = {}, + state = InputShellState.UNFOCUSED, ) Spacer(Modifier.size(Spacing.Spacing18)) @@ -51,6 +52,7 @@ fun InputLinkScreen() { } }, onLinkActionCLicked = {}, + state = InputShellState.UNFOCUSED, ) Spacer(Modifier.size(Spacing.Spacing18)) @@ -67,6 +69,7 @@ fun InputLinkScreen() { } }, onLinkActionCLicked = {}, + state = InputShellState.UNFOCUSED, ) Spacer(Modifier.size(Spacing.Spacing18)) diff --git a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputLongTextScreen.kt b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputLongTextScreen.kt index 9880f2c7d..a31f08a1f 100644 --- a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputLongTextScreen.kt +++ b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputLongTextScreen.kt @@ -38,6 +38,7 @@ fun InputLongTextScreen() { inputValue1 = it } }, + state = InputShellState.UNFOCUSED, ) Spacer(Modifier.size(Spacing.Spacing18)) diff --git a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputMatrixScreen.kt b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputMatrixScreen.kt index 32ddc314f..fde6479f8 100644 --- a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputMatrixScreen.kt +++ b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputMatrixScreen.kt @@ -70,6 +70,7 @@ fun InputMatrixScreen() { newSelectedItem } }, + state = InputShellState.UNFOCUSED, ) InputMatrix( diff --git a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputNegativeIntegerScreen.kt b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputNegativeIntegerScreen.kt index 6349f906c..2883bbb15 100644 --- a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputNegativeIntegerScreen.kt +++ b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputNegativeIntegerScreen.kt @@ -33,6 +33,7 @@ fun InputNegativeIntegerScreen() { inputValue1 = it } }, + state = InputShellState.UNFOCUSED, ) Spacer(Modifier.size(Spacing.Spacing18)) diff --git a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputNumberScreen.kt b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputNumberScreen.kt index 8c9964929..530429cdf 100644 --- a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputNumberScreen.kt +++ b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputNumberScreen.kt @@ -34,6 +34,7 @@ fun InputNumberScreen() { } }, notation = RegExValidations.BRITISH_DECIMAL_NOTATION, + state = InputShellState.UNFOCUSED, ) Spacer(Modifier.size(Spacing.Spacing18)) @@ -49,6 +50,7 @@ fun InputNumberScreen() { } }, notation = RegExValidations.EUROPEAN_DECIMAL_NOTATION, + state = InputShellState.UNFOCUSED, ) Spacer(Modifier.size(Spacing.Spacing18)) diff --git a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputPercentageScreen.kt b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputPercentageScreen.kt index 7013cff13..79c340854 100644 --- a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputPercentageScreen.kt +++ b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputPercentageScreen.kt @@ -31,6 +31,7 @@ fun InputPercentageScreen() { inputValue1 = it } }, + state = InputShellState.UNFOCUSED, ) Spacer(Modifier.size(Spacing.Spacing18)) diff --git a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputPhoneNumberScreen.kt b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputPhoneNumberScreen.kt index 850ec3a70..68872471f 100644 --- a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputPhoneNumberScreen.kt +++ b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputPhoneNumberScreen.kt @@ -34,6 +34,7 @@ fun InputPhoneNumberScreen() { // no-op }, onFocusChanged = {}, + state = InputShellState.UNFOCUSED, ) Spacer(Modifier.size(Spacing.Spacing18)) diff --git a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputPositiveIntegerOrZeroScreen.kt b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputPositiveIntegerOrZeroScreen.kt index e25077ed0..3e12e4e6b 100644 --- a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputPositiveIntegerOrZeroScreen.kt +++ b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputPositiveIntegerOrZeroScreen.kt @@ -33,6 +33,7 @@ fun InputPositiveIntegerOrZeroScreen() { inputValue1 = it } }, + state = InputShellState.UNFOCUSED, ) Spacer(Modifier.size(Spacing.Spacing18)) diff --git a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputPositiveIntegerScreen.kt b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputPositiveIntegerScreen.kt index 5394a7a68..793f63ced 100644 --- a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputPositiveIntegerScreen.kt +++ b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputPositiveIntegerScreen.kt @@ -33,6 +33,7 @@ fun InputPositiveIntegerScreen() { inputValue1 = it } }, + state = InputShellState.UNFOCUSED, ) Spacer(Modifier.size(Spacing.Spacing18)) SubTitle("Basic Input Integer with error", textColor = TextColor.OnSurfaceVariant) diff --git a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputRadioButtonScreen.kt b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputRadioButtonScreen.kt index 03722fac3..f189e1fb5 100644 --- a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputRadioButtonScreen.kt +++ b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputRadioButtonScreen.kt @@ -76,6 +76,7 @@ fun InputRadioButtonScreen() { onItemChange = { selectedItemVertical = it }, + state = InputShellState.UNFOCUSED, ) Spacer(Modifier.size(Spacing.Spacing18)) InputRadioButton( @@ -106,6 +107,7 @@ fun InputRadioButtonScreen() { onItemChange = { selectedItemHorizontal = it }, + state = InputShellState.UNFOCUSED, ) } } diff --git a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputSequentialScreen.kt b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputSequentialScreen.kt index 4ae53d27a..2dffac55b 100644 --- a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputSequentialScreen.kt +++ b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputSequentialScreen.kt @@ -70,6 +70,7 @@ fun InputSequentialScreen() { newSelectedItem } }, + state = InputShellState.UNFOCUSED, ) InputSequential( diff --git a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputTextScreen.kt b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputTextScreen.kt index c56b6e80b..d86cbc6a8 100644 --- a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputTextScreen.kt +++ b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputTextScreen.kt @@ -31,6 +31,7 @@ fun InputTextScreen() { inputValue1 = it } }, + state = InputShellState.UNFOCUSED, ) Spacer(Modifier.size(Spacing.Spacing18)) SubTitle("Input text with error ") diff --git a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputYesNoFieldScreen.kt b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputYesNoFieldScreen.kt index 5afdb21ca..eeec96866 100644 --- a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputYesNoFieldScreen.kt +++ b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputYesNoFieldScreen.kt @@ -37,6 +37,7 @@ fun InputYesNoFieldScreen() { onItemChange = { selectedItem = it }, + state = InputShellState.UNFOCUSED, ) Spacer(Modifier.size(Spacing.Spacing18)) InputYesNoField( @@ -45,6 +46,7 @@ fun InputYesNoFieldScreen() { onItemChange = { selectedItem1 = it }, + state = InputShellState.UNFOCUSED, ) Spacer(Modifier.size(Spacing.Spacing18)) InputYesNoField( diff --git a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputYesOnlyCheckBoxScreen.kt b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputYesOnlyCheckBoxScreen.kt index 28d696806..77d53c00b 100644 --- a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputYesOnlyCheckBoxScreen.kt +++ b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputYesOnlyCheckBoxScreen.kt @@ -28,20 +28,22 @@ fun InputYesOnlyCheckBoxScreen() { var checkboxData2 by rememberSaveable { mutableStateOf(CheckBoxData(uid = "0", checked = false, enabled = true, textInput = "Label")) } - var checkboxData3 by rememberSaveable { + val checkboxData3 by rememberSaveable { mutableStateOf(CheckBoxData(uid = "0", checked = false, enabled = true, textInput = "Label")) } - var checkboxData4 by rememberSaveable { + val checkboxData4 by rememberSaveable { mutableStateOf(CheckBoxData(uid = "0", checked = true, enabled = true, textInput = "Label")) } InputYesOnlyCheckBox( checkBoxData = checkboxData, + state = InputShellState.UNFOCUSED, ) { checkboxData = checkboxData.copy(checked = !checkboxData.checked) } Spacer(Modifier.size(Spacing.Spacing18)) InputYesOnlyCheckBox( checkBoxData = checkboxData1, + state = InputShellState.UNFOCUSED, ) { checkboxData1 = checkboxData1.copy(checked = !checkboxData.checked) } diff --git a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputYesOnlySwitchScreen.kt b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputYesOnlySwitchScreen.kt index d554234af..af1980e73 100644 --- a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputYesOnlySwitchScreen.kt +++ b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputYesOnlySwitchScreen.kt @@ -26,6 +26,7 @@ fun InputYesOnlySwitchScreen() { InputYesOnlySwitch( title = "Label", isChecked = isSelected, + state = InputShellState.UNFOCUSED, ) { isSelected = !isSelected } @@ -33,6 +34,7 @@ fun InputYesOnlySwitchScreen() { InputYesOnlySwitch( title = "Label", isChecked = isSelected1, + state = InputShellState.UNFOCUSED, ) { isSelected1 = !isSelected1 } diff --git a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/SectionScreen.kt b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/SectionScreen.kt index 2a9d7ad89..2313dd06e 100644 --- a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/SectionScreen.kt +++ b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/SectionScreen.kt @@ -13,6 +13,7 @@ import org.hisp.dhis.common.screens.previews.lorem import org.hisp.dhis.common.screens.previews.lorem_medium import org.hisp.dhis.common.screens.previews.lorem_short import org.hisp.dhis.mobile.ui.designsystem.component.ColumnComponentContainer +import org.hisp.dhis.mobile.ui.designsystem.component.InputShellState import org.hisp.dhis.mobile.ui.designsystem.component.InputText import org.hisp.dhis.mobile.ui.designsystem.component.Section import org.hisp.dhis.mobile.ui.designsystem.component.SectionState @@ -162,15 +163,18 @@ private fun TestingFields() { title = "Label", inputText = inputValue1, onValueChanged = { inputValue1 = it ?: "" }, + state = InputShellState.UNFOCUSED, ) InputText( title = "Label", inputText = inputValue2, onValueChanged = { inputValue2 = it ?: "" }, + state = InputShellState.UNFOCUSED, ) InputText( title = "Label", inputText = inputValue3, onValueChanged = { inputValue3 = it ?: "" }, + state = InputShellState.UNFOCUSED, ) } diff --git a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/BasicTextInput.kt b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/BasicTextInput.kt index 25b57fc36..eca11ad75 100644 --- a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/BasicTextInput.kt +++ b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/BasicTextInput.kt @@ -41,7 +41,7 @@ import java.util.Locale @Composable internal fun BasicTextInput( title: String, - state: InputShellState = InputShellState.UNFOCUSED, + state: InputShellState, supportingText: List? = null, legendData: LegendData? = null, inputText: String? = null, diff --git a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputCheckBox.kt b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputCheckBox.kt index dc8452d62..5d4d0786b 100644 --- a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputCheckBox.kt +++ b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputCheckBox.kt @@ -32,7 +32,7 @@ fun InputCheckBox( checkBoxData: List, modifier: Modifier = Modifier, orientation: Orientation = Orientation.VERTICAL, - state: InputShellState = InputShellState.UNFOCUSED, + state: InputShellState, supportingText: List? = null, legendData: LegendData? = null, isRequired: Boolean = false, diff --git a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputEmail.kt b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputEmail.kt index d674860db..e43ded9d0 100644 --- a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputEmail.kt +++ b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputEmail.kt @@ -31,7 +31,7 @@ import org.hisp.dhis.mobile.ui.designsystem.component.internal.RegExValidations @Composable fun InputEmail( title: String, - state: InputShellState = InputShellState.UNFOCUSED, + state: InputShellState, supportingText: List? = null, legendData: LegendData? = null, inputText: String? = null, diff --git a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputInteger.kt b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputInteger.kt index 53909baf5..baa5c0054 100644 --- a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputInteger.kt +++ b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputInteger.kt @@ -27,7 +27,7 @@ import org.hisp.dhis.mobile.ui.designsystem.component.internal.RegExValidations @Composable fun InputInteger( title: String, - state: InputShellState = InputShellState.UNFOCUSED, + state: InputShellState, supportingText: List? = null, legendData: LegendData? = null, inputText: String? = null, diff --git a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputLetter.kt b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputLetter.kt index a0dc99544..5304e6a6c 100644 --- a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputLetter.kt +++ b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputLetter.kt @@ -29,7 +29,7 @@ import org.hisp.dhis.mobile.ui.designsystem.component.internal.RegExValidations @Composable fun InputLetter( title: String, - state: InputShellState = InputShellState.UNFOCUSED, + state: InputShellState, supportingText: List? = null, legendData: LegendData? = null, inputText: String? = null, diff --git a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputLink.kt b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputLink.kt index 305d732bf..7ea5f7e3a 100644 --- a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputLink.kt +++ b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputLink.kt @@ -31,7 +31,7 @@ import org.hisp.dhis.mobile.ui.designsystem.component.internal.RegExValidations @Composable fun InputLink( title: String, - state: InputShellState = InputShellState.UNFOCUSED, + state: InputShellState, supportingText: List? = null, legendData: LegendData? = null, inputText: String? = null, diff --git a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputLongText.kt b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputLongText.kt index 72e5f691a..0c2d508f8 100644 --- a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputLongText.kt +++ b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputLongText.kt @@ -30,7 +30,7 @@ import org.hisp.dhis.mobile.ui.designsystem.theme.Spacing @Composable fun InputLongText( title: String, - state: InputShellState = InputShellState.UNFOCUSED, + state: InputShellState, supportingText: List? = null, legendData: LegendData? = null, inputText: String? = null, diff --git a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputMatrix.kt b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputMatrix.kt index 41f63699f..dfe7af4a2 100644 --- a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputMatrix.kt +++ b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputMatrix.kt @@ -14,7 +14,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.testTag -import org.hisp.dhis.mobile.ui.designsystem.component.InputShellState.UNFOCUSED import org.hisp.dhis.mobile.ui.designsystem.component.internal.IconCard import org.hisp.dhis.mobile.ui.designsystem.component.internal.IconCardData import org.hisp.dhis.mobile.ui.designsystem.component.internal.VerticalGrid @@ -42,7 +41,7 @@ fun InputMatrix( itemCount: Int = 2, selectedData: IconCardData? = null, modifier: Modifier = Modifier, - state: InputShellState = UNFOCUSED, + state: InputShellState, supportingText: List? = null, legendData: LegendData? = null, isRequired: Boolean = false, diff --git a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputNegativeInteger.kt b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputNegativeInteger.kt index 1f5753644..f30d23516 100644 --- a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputNegativeInteger.kt +++ b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputNegativeInteger.kt @@ -31,7 +31,7 @@ import org.hisp.dhis.mobile.ui.designsystem.component.internal.RegExValidations @Composable fun InputNegativeInteger( title: String, - state: InputShellState = InputShellState.UNFOCUSED, + state: InputShellState, supportingText: List? = null, legendData: LegendData? = null, inputText: String? = null, diff --git a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputNumber.kt b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputNumber.kt index 1ca6f04d0..047610be6 100644 --- a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputNumber.kt +++ b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputNumber.kt @@ -29,7 +29,7 @@ import org.hisp.dhis.mobile.ui.designsystem.component.internal.RegExValidations @Composable fun InputNumber( title: String, - state: InputShellState = InputShellState.UNFOCUSED, + state: InputShellState, supportingText: List? = null, legendData: LegendData? = null, inputText: String? = null, diff --git a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputPercentage.kt b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputPercentage.kt index f585c2fa5..91e16b97a 100644 --- a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputPercentage.kt +++ b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputPercentage.kt @@ -27,7 +27,7 @@ import org.hisp.dhis.mobile.ui.designsystem.component.internal.RegExValidations @Composable fun InputPercentage( title: String, - state: InputShellState = InputShellState.UNFOCUSED, + state: InputShellState, supportingText: List? = null, legendData: LegendData? = null, inputText: String? = null, diff --git a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputPhoneNumber.kt b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputPhoneNumber.kt index ea75698f2..24b5e74c9 100644 --- a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputPhoneNumber.kt +++ b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputPhoneNumber.kt @@ -10,7 +10,6 @@ import androidx.compose.ui.platform.testTag import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType import org.hisp.dhis.mobile.ui.designsystem.component.internal.RegExValidations -import org.hisp.dhis.mobile.ui.designsystem.resource.provideStringResource /** * DHIS2 Input Phone Number @@ -35,7 +34,7 @@ fun InputPhoneNumber( onCallActionClicked: () -> Unit, modifier: Modifier = Modifier, maxLength: Int = 12, - state: InputShellState = InputShellState.UNFOCUSED, + state: InputShellState, legendData: LegendData? = null, inputText: String? = null, isRequiredField: Boolean = false, @@ -43,20 +42,9 @@ fun InputPhoneNumber( onValueChanged: ((String?) -> Unit)? = null, onFocusChanged: ((Boolean) -> Unit) = {}, imeAction: ImeAction = ImeAction.Next, - errorMessage: String = provideStringResource("enter_phone_number"), + supportingText: List? = emptyList(), allowedCharacters: RegExValidations = RegExValidations.PHONE_NUMBER, ) { - val supportingText = if (state == InputShellState.ERROR) { - listOf( - SupportingTextData( - text = errorMessage, - state = SupportingTextState.ERROR, - ), - ) - } else { - emptyList() - } - BasicTextInput( title = title, state = state, @@ -88,7 +76,6 @@ fun InputPhoneNumber( }, onClick = { onCallActionClicked.invoke() - onFocusChanged(true) }, ) }, diff --git a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputPositiveInteger.kt b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputPositiveInteger.kt index 10224b5e6..f7cad92ff 100644 --- a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputPositiveInteger.kt +++ b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputPositiveInteger.kt @@ -27,7 +27,7 @@ import org.hisp.dhis.mobile.ui.designsystem.component.internal.RegExValidations @Composable fun InputPositiveInteger( title: String, - state: InputShellState = InputShellState.UNFOCUSED, + state: InputShellState, supportingText: List? = null, legendData: LegendData? = null, inputText: String? = null, diff --git a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputPositiveIntegerOrZero.kt b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputPositiveIntegerOrZero.kt index 615466cb3..359da11eb 100644 --- a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputPositiveIntegerOrZero.kt +++ b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputPositiveIntegerOrZero.kt @@ -27,7 +27,7 @@ import org.hisp.dhis.mobile.ui.designsystem.component.internal.RegExValidations @Composable fun InputPositiveIntegerOrZero( title: String, - state: InputShellState = InputShellState.UNFOCUSED, + state: InputShellState, supportingText: List? = null, legendData: LegendData? = null, inputText: String? = null, diff --git a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputQRCode.kt b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputQRCode.kt index 3edd753e8..d0e697127 100644 --- a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputQRCode.kt +++ b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputQRCode.kt @@ -3,8 +3,10 @@ package org.hisp.dhis.mobile.ui.designsystem.component import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.QrCode2 +import androidx.compose.material.icons.outlined.QrCodeScanner import androidx.compose.material3.Icon import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf import androidx.compose.ui.Modifier import androidx.compose.ui.platform.testTag import androidx.compose.ui.text.input.ImeAction @@ -29,7 +31,7 @@ import androidx.compose.ui.text.input.ImeAction @Composable fun InputQRCode( title: String, - state: InputShellState = InputShellState.UNFOCUSED, + state: InputShellState, onQRButtonClicked: () -> Unit, supportingText: List? = null, legendData: LegendData? = null, @@ -41,6 +43,7 @@ fun InputQRCode( imeAction: ImeAction = ImeAction.Next, modifier: Modifier = Modifier, ) { + val actionButtonIconVector = mutableStateOf(if (!inputText.isNullOrEmpty()) Icons.Outlined.QrCode2 else Icons.Outlined.QrCodeScanner) BasicTextInput( title = title, state = state, @@ -60,7 +63,7 @@ fun InputQRCode( enabled = true, icon = { Icon( - imageVector = Icons.Outlined.QrCode2, + imageVector = actionButtonIconVector.value, contentDescription = null, ) }, diff --git a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputRadioButton.kt b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputRadioButton.kt index 110dc1e75..e489feb79 100644 --- a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputRadioButton.kt +++ b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputRadioButton.kt @@ -9,7 +9,6 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.platform.testTag import org.hisp.dhis.mobile.ui.designsystem.component.InputShellState.DISABLED -import org.hisp.dhis.mobile.ui.designsystem.component.InputShellState.UNFOCUSED import org.hisp.dhis.mobile.ui.designsystem.component.Orientation.VERTICAL import org.hisp.dhis.mobile.ui.designsystem.theme.Spacing @@ -36,7 +35,7 @@ fun InputRadioButton( radioButtonData: List, modifier: Modifier = Modifier, orientation: Orientation = VERTICAL, - state: InputShellState = UNFOCUSED, + state: InputShellState, supportingText: List? = null, legendData: LegendData? = null, isRequired: Boolean = false, diff --git a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputSequential.kt b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputSequential.kt index 8a05dcc3a..a70047663 100644 --- a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputSequential.kt +++ b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputSequential.kt @@ -15,7 +15,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.testTag -import org.hisp.dhis.mobile.ui.designsystem.component.InputShellState.UNFOCUSED import org.hisp.dhis.mobile.ui.designsystem.component.internal.IconCard import org.hisp.dhis.mobile.ui.designsystem.component.internal.IconCardData import org.hisp.dhis.mobile.ui.designsystem.resource.provideDHIS2Icon @@ -41,7 +40,7 @@ fun InputSequential( data: List, selectedData: IconCardData? = null, modifier: Modifier = Modifier, - state: InputShellState = UNFOCUSED, + state: InputShellState, supportingText: List? = null, legendData: LegendData? = null, isRequired: Boolean = false, diff --git a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputShell.kt b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputShell.kt index 8825c14af..dda616f85 100644 --- a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputShell.kt +++ b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputShell.kt @@ -47,7 +47,7 @@ import org.hisp.dhis.mobile.ui.designsystem.theme.TextColor @Composable fun InputShell( title: String, - state: InputShellState = InputShellState.UNFOCUSED, + state: InputShellState, primaryButton: @Composable (() -> Unit)? = null, secondaryButton: @Composable (() -> Unit)? = null, inputField: @Composable (() -> Unit)? = null, diff --git a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputText.kt b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputText.kt index d8d2e910f..e2ab9ed62 100644 --- a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputText.kt +++ b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputText.kt @@ -24,7 +24,7 @@ import androidx.compose.ui.text.input.ImeAction @Composable fun InputText( title: String, - state: InputShellState = InputShellState.UNFOCUSED, + state: InputShellState, supportingText: List? = null, legendData: LegendData? = null, inputText: String? = null, diff --git a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputYesNoField.kt b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputYesNoField.kt index 693e2d13e..46e7ff045 100644 --- a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputYesNoField.kt +++ b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputYesNoField.kt @@ -28,7 +28,7 @@ import java.util.Locale fun InputYesNoField( title: String, modifier: Modifier = Modifier, - state: InputShellState = InputShellState.UNFOCUSED, + state: InputShellState, supportingText: List? = null, legendData: LegendData? = null, isRequired: Boolean = false, diff --git a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputYesOnlyCheckBox.kt b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputYesOnlyCheckBox.kt index 30f40a8bc..65f4cb4f2 100644 --- a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputYesOnlyCheckBox.kt +++ b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputYesOnlyCheckBox.kt @@ -16,7 +16,7 @@ import org.hisp.dhis.mobile.ui.designsystem.theme.Spacing fun InputYesOnlyCheckBox( checkBoxData: CheckBoxData, modifier: Modifier = Modifier, - state: InputShellState = InputShellState.UNFOCUSED, + state: InputShellState, supportingText: List? = null, legendData: LegendData? = null, isRequired: Boolean = false, diff --git a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputYesOnlySwitch.kt b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputYesOnlySwitch.kt index 69d83f11d..e561852c9 100644 --- a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputYesOnlySwitch.kt +++ b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputYesOnlySwitch.kt @@ -19,7 +19,7 @@ import org.hisp.dhis.mobile.ui.designsystem.theme.Spacing fun InputYesOnlySwitch( title: String, modifier: Modifier = Modifier, - state: InputShellState = InputShellState.UNFOCUSED, + state: InputShellState, supportingText: List? = null, legendData: LegendData? = null, isRequired: Boolean = false, diff --git a/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputCheckBoxTest.kt b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputCheckBoxTest.kt index e848bd24d..aa333c095 100644 --- a/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputCheckBoxTest.kt +++ b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputCheckBoxTest.kt @@ -41,6 +41,7 @@ class InputCheckBoxTest { checkBoxDataList[index] = checkBoxData.copy(checked = !checkBoxData.checked) }, onClearSelection = { checkBoxDataList.replaceAll { it.copy(checked = false) } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_CHECK_BOX").assertExists() @@ -68,6 +69,7 @@ class InputCheckBoxTest { checkBoxDataList[index] = checkBoxData.copy(checked = !checkBoxData.checked) }, onClearSelection = { checkBoxDataList.replaceAll { it.copy(checked = false) } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_CHECK_BOX").assertExists() @@ -121,6 +123,7 @@ class InputCheckBoxTest { checkBoxDataList[index] = checkBoxData.copy(checked = !checkBoxData.checked) }, onClearSelection = { checkBoxDataList.replaceAll { it.copy(checked = false) } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_CHECK_BOX").assertExists() @@ -147,6 +150,7 @@ class InputCheckBoxTest { checkBoxDataList[index] = checkBoxData.copy(checked = !checkBoxData.checked) }, onClearSelection = { checkBoxDataList.replaceAll { it.copy(checked = false) } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_CHECK_BOX").assertExists() @@ -197,6 +201,7 @@ class InputCheckBoxTest { checkBoxDataList[index] = checkBoxData.copy(checked = !checkBoxData.checked) }, onClearSelection = { checkBoxDataList.replaceAll { it.copy(checked = false) } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_CHECK_BOX").assertExists() @@ -224,6 +229,7 @@ class InputCheckBoxTest { legendData = LegendData(SurfaceColor.CustomGreen, "Legend"), onItemChange = { }, onClearSelection = { }, + state = InputShellState.UNFOCUSED, ) } @@ -249,6 +255,7 @@ class InputCheckBoxTest { supportingText = listOf(SupportingTextData("Supporting text", SupportingTextState.DEFAULT)), onItemChange = { }, onClearSelection = { }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_CHECK_BOX").assertExists() diff --git a/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputEmailTest.kt b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputEmailTest.kt index ddd9ee40e..4d8ba0cf6 100644 --- a/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputEmailTest.kt +++ b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputEmailTest.kt @@ -30,6 +30,7 @@ class InputEmailTest { InputEmail( title = "Label", onEmailActionCLicked = {}, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_EMAIL").assertExists() @@ -50,6 +51,7 @@ class InputEmailTest { } }, onEmailActionCLicked = {}, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_EMAIL").assertExists() @@ -83,6 +85,7 @@ class InputEmailTest { } }, onEmailActionCLicked = {}, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_EMAIL").assertExists() @@ -105,6 +108,7 @@ class InputEmailTest { } }, onEmailActionCLicked = {}, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_EMAIL").assertExists() @@ -142,6 +146,7 @@ class InputEmailTest { inputText = "Input", legendData = LegendData(SurfaceColor.CustomGreen, "Legend"), onEmailActionCLicked = {}, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_EMAIL").assertExists() @@ -157,6 +162,7 @@ class InputEmailTest { inputText = "Input", supportingText = listOf(SupportingTextData("Supporting text", SupportingTextState.DEFAULT)), onEmailActionCLicked = {}, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_EMAIL").assertExists() @@ -177,6 +183,7 @@ class InputEmailTest { } }, onEmailActionCLicked = {}, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("EMAIL_BUTTON").assertIsNotEnabled() @@ -211,6 +218,7 @@ class InputEmailTest { } }, onEmailActionCLicked = {}, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("EMAIL_BUTTON").assertIsEnabled() diff --git a/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputIntegerTest.kt b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputIntegerTest.kt index 8c0810df6..09f922f53 100644 --- a/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputIntegerTest.kt +++ b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputIntegerTest.kt @@ -27,6 +27,7 @@ class InputIntegerTest { rule.setContent { InputInteger( title = "Label", + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_INTEGER").assertExists() @@ -46,6 +47,7 @@ class InputIntegerTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_INTEGER").assertExists() @@ -77,6 +79,7 @@ class InputIntegerTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_INTEGER").assertExists() @@ -98,6 +101,7 @@ class InputIntegerTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_INTEGER").assertExists() @@ -114,6 +118,7 @@ class InputIntegerTest { title = "Label", inputText = "Input", legendData = LegendData(SurfaceColor.CustomGreen, "Legend"), + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_INTEGER").assertExists() @@ -128,6 +133,7 @@ class InputIntegerTest { title = "Label", inputText = "Input", supportingText = listOf(SupportingTextData("Supporting text", SupportingTextState.DEFAULT)), + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_INTEGER").assertExists() @@ -146,6 +152,7 @@ class InputIntegerTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_INTEGER").assertExists() @@ -166,6 +173,7 @@ class InputIntegerTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_INTEGER").assertExists() @@ -186,6 +194,7 @@ class InputIntegerTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_INTEGER").assertExists() diff --git a/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputLetterTest.kt b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputLetterTest.kt index 958649bde..0ee982ec8 100644 --- a/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputLetterTest.kt +++ b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputLetterTest.kt @@ -30,6 +30,7 @@ class InputLetterTest { InputLetter( title = "Label", modifier = Modifier.testTag("INPUT_LETTER"), + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_LETTER").assertExists() @@ -50,6 +51,7 @@ class InputLetterTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_LETTER").assertExists() @@ -83,6 +85,7 @@ class InputLetterTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_LETTER").assertExists() @@ -105,6 +108,7 @@ class InputLetterTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_LETTER").assertExists() @@ -122,6 +126,7 @@ class InputLetterTest { modifier = Modifier.testTag("INPUT_LETTER"), inputText = "Input", legendData = LegendData(SurfaceColor.CustomGreen, "Legend"), + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_LETTER").assertExists() @@ -137,6 +142,7 @@ class InputLetterTest { modifier = Modifier.testTag("INPUT_LETTER"), inputText = "Input", supportingText = listOf(SupportingTextData("Supporting text", SupportingTextState.DEFAULT)), + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_LETTER").assertExists() @@ -156,6 +162,7 @@ class InputLetterTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_LETTER").assertExists() diff --git a/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputLinkTest.kt b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputLinkTest.kt index b8c197832..bdf4dcdc7 100644 --- a/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputLinkTest.kt +++ b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputLinkTest.kt @@ -31,6 +31,7 @@ class InputLinkTest { InputLink( title = "Label", onLinkActionCLicked = {}, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_LINK").assertExists() @@ -51,6 +52,7 @@ class InputLinkTest { } }, onLinkActionCLicked = {}, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_LINK").assertExists() @@ -84,6 +86,7 @@ class InputLinkTest { } }, onLinkActionCLicked = {}, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_LINK").assertExists() @@ -106,6 +109,7 @@ class InputLinkTest { } }, onLinkActionCLicked = {}, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_LINK").assertExists() @@ -143,6 +147,7 @@ class InputLinkTest { inputText = "Input", legendData = LegendData(SurfaceColor.CustomGreen, "Legend"), onLinkActionCLicked = {}, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_LINK").assertExists() @@ -158,6 +163,7 @@ class InputLinkTest { inputText = "Input", supportingText = listOf(SupportingTextData("Supporting text", SupportingTextState.DEFAULT)), onLinkActionCLicked = {}, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_LINK").assertExists() @@ -178,6 +184,7 @@ class InputLinkTest { } }, onLinkActionCLicked = {}, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("LINK_BUTTON").assertIsNotEnabled() @@ -212,6 +219,7 @@ class InputLinkTest { } }, onLinkActionCLicked = {}, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("LINK_BUTTON").assertIsEnabled() diff --git a/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputLongTextTest.kt b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputLongTextTest.kt index c34765c52..c1e91f0ac 100644 --- a/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputLongTextTest.kt +++ b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputLongTextTest.kt @@ -30,6 +30,7 @@ class InputLongTextTest { InputLongText( title = "Label", modifier = Modifier.testTag("INPUT_LONG_TEXT"), + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_LONG_TEXT").assertExists() @@ -50,6 +51,7 @@ class InputLongTextTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_LONG_TEXT").assertExists() @@ -83,6 +85,7 @@ class InputLongTextTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_LONG_TEXT").assertExists() @@ -105,6 +108,7 @@ class InputLongTextTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_LONG_TEXT").assertExists() @@ -122,6 +126,7 @@ class InputLongTextTest { modifier = Modifier.testTag("INPUT_LONG_TEXT"), inputText = "Input", legendData = LegendData(SurfaceColor.CustomGreen, "Legend"), + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_LONG_TEXT").assertExists() @@ -137,6 +142,7 @@ class InputLongTextTest { modifier = Modifier.testTag("INPUT_LONG_TEXT"), inputText = "Input", supportingText = listOf(SupportingTextData("Supporting text", SupportingTextState.DEFAULT)), + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_LONG_TEXT").assertExists() diff --git a/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputNegativeIntegerTest.kt b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputNegativeIntegerTest.kt index 7733b0aec..d7ff0564c 100644 --- a/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputNegativeIntegerTest.kt +++ b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputNegativeIntegerTest.kt @@ -26,6 +26,7 @@ class InputNegativeIntegerTest { rule.setContent { InputNegativeInteger( title = "Label", + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_NEGATIVE_INTEGER").assertExists() @@ -45,6 +46,7 @@ class InputNegativeIntegerTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_NEGATIVE_INTEGER").assertExists() @@ -76,6 +78,7 @@ class InputNegativeIntegerTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_NEGATIVE_INTEGER").assertExists() @@ -97,6 +100,7 @@ class InputNegativeIntegerTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_NEGATIVE_INTEGER").assertExists() @@ -112,6 +116,7 @@ class InputNegativeIntegerTest { title = "Label", inputText = "", legendData = LegendData(SurfaceColor.CustomGreen, "Legend"), + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_NEGATIVE_INTEGER").assertExists() @@ -126,6 +131,7 @@ class InputNegativeIntegerTest { title = "Label", inputText = "", supportingText = listOf(SupportingTextData("Supporting text", SupportingTextState.DEFAULT)), + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_NEGATIVE_INTEGER").assertExists() @@ -144,6 +150,7 @@ class InputNegativeIntegerTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_NEGATIVE_INTEGER").assertExists() @@ -163,6 +170,7 @@ class InputNegativeIntegerTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_NEGATIVE_INTEGER").assertExists() diff --git a/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputNumberTest.kt b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputNumberTest.kt index 6bace7313..a7645c247 100644 --- a/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputNumberTest.kt +++ b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputNumberTest.kt @@ -30,6 +30,7 @@ class InputNumberTest { InputNumber( title = "Label", modifier = Modifier.testTag("INPUT_NUMBER"), + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_NUMBER").assertExists() @@ -50,6 +51,7 @@ class InputNumberTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_NUMBER").assertExists() @@ -83,6 +85,7 @@ class InputNumberTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_NUMBER").assertExists() @@ -105,6 +108,7 @@ class InputNumberTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_NUMBER").assertExists() @@ -122,6 +126,7 @@ class InputNumberTest { modifier = Modifier.testTag("INPUT_NUMBER"), inputText = "", legendData = LegendData(SurfaceColor.CustomGreen, "Legend"), + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_NUMBER").assertExists() @@ -137,6 +142,7 @@ class InputNumberTest { modifier = Modifier.testTag("INPUT_NUMBER"), inputText = "", supportingText = listOf(SupportingTextData("Supporting text", SupportingTextState.DEFAULT)), + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_NUMBER").assertExists() @@ -156,6 +162,7 @@ class InputNumberTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_NUMBER").assertExists() diff --git a/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputPercentageTest.kt b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputPercentageTest.kt index e8598ec95..5d5ae0dd7 100644 --- a/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputPercentageTest.kt +++ b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputPercentageTest.kt @@ -27,6 +27,7 @@ class InputPercentageTest { rule.setContent { InputPercentage( title = "Label", + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_PERCENTAGE").assertExists() @@ -46,6 +47,7 @@ class InputPercentageTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_PERCENTAGE").assertExists() @@ -77,6 +79,7 @@ class InputPercentageTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_PERCENTAGE").assertExists() @@ -98,6 +101,7 @@ class InputPercentageTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_PERCENTAGE").assertExists() @@ -113,6 +117,7 @@ class InputPercentageTest { title = "Label", inputText = "", legendData = LegendData(SurfaceColor.CustomGreen, "Legend"), + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_PERCENTAGE").assertExists() @@ -127,6 +132,7 @@ class InputPercentageTest { title = "Label", inputText = "", supportingText = listOf(SupportingTextData("Supporting text", SupportingTextState.DEFAULT)), + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_PERCENTAGE").assertExists() @@ -145,6 +151,7 @@ class InputPercentageTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_PERCENTAGE").assertExists() @@ -164,6 +171,7 @@ class InputPercentageTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_PERCENTAGE").assertExists() diff --git a/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputPhoneNumberTest.kt b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputPhoneNumberTest.kt index c311b8a03..d7cf654e1 100644 --- a/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputPhoneNumberTest.kt +++ b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputPhoneNumberTest.kt @@ -33,6 +33,7 @@ class InputPhoneNumberTest { onCallActionClicked = { // no-op }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_PHONE_NUMBER_FIELD").assertTextEquals("") @@ -43,7 +44,7 @@ class InputPhoneNumberTest { } @Test - fun shouldDisplaySupportTextIfInputStateIsError() { + fun shouldDisplaySupportText() { rule.setContent { InputPhoneNumber( title = "Phone Number", @@ -70,6 +71,7 @@ class InputPhoneNumberTest { onCallActionClicked = { // no-op }, + supportingText = listOf(SupportingTextData("Error", SupportingTextState.ERROR)), ) } rule.onNodeWithTag("INPUT_PHONE_NUMBER_SUPPORTING_TEXT").assertExists() @@ -89,6 +91,7 @@ class InputPhoneNumberTest { onCallActionClicked = { // no-op }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_PHONE_NUMBER_RESET_BUTTON").assertExists() diff --git a/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputPositiveIntegerOrZeroTest.kt b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputPositiveIntegerOrZeroTest.kt index 45069ad3b..35224b3ae 100644 --- a/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputPositiveIntegerOrZeroTest.kt +++ b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputPositiveIntegerOrZeroTest.kt @@ -27,6 +27,7 @@ class InputPositiveIntegerOrZeroTest { rule.setContent { InputPositiveIntegerOrZero( title = "Label", + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_POSITIVE_INTEGER_OR_ZERO").assertExists() @@ -46,6 +47,7 @@ class InputPositiveIntegerOrZeroTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_POSITIVE_INTEGER_OR_ZERO").assertExists() @@ -77,6 +79,7 @@ class InputPositiveIntegerOrZeroTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_POSITIVE_INTEGER_OR_ZERO").assertExists() @@ -98,6 +101,7 @@ class InputPositiveIntegerOrZeroTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_POSITIVE_INTEGER_OR_ZERO").assertExists() @@ -114,6 +118,7 @@ class InputPositiveIntegerOrZeroTest { title = "Label", inputText = "", legendData = LegendData(SurfaceColor.CustomGreen, "Legend"), + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_POSITIVE_INTEGER_OR_ZERO").assertExists() @@ -128,6 +133,7 @@ class InputPositiveIntegerOrZeroTest { title = "Label", inputText = "", supportingText = listOf(SupportingTextData("Supporting text", SupportingTextState.DEFAULT)), + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_POSITIVE_INTEGER_OR_ZERO").assertExists() @@ -146,6 +152,7 @@ class InputPositiveIntegerOrZeroTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_POSITIVE_INTEGER_OR_ZERO").assertExists() @@ -165,6 +172,7 @@ class InputPositiveIntegerOrZeroTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_POSITIVE_INTEGER_OR_ZERO").assertExists() @@ -184,6 +192,7 @@ class InputPositiveIntegerOrZeroTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_POSITIVE_INTEGER_OR_ZERO").assertExists() @@ -203,6 +212,7 @@ class InputPositiveIntegerOrZeroTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_POSITIVE_INTEGER_OR_ZERO").assertExists() diff --git a/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputPositiveIntegerTest.kt b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputPositiveIntegerTest.kt index d329b4bc9..1a2663dab 100644 --- a/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputPositiveIntegerTest.kt +++ b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputPositiveIntegerTest.kt @@ -27,6 +27,7 @@ class InputPositiveIntegerTest { rule.setContent { InputPositiveInteger( title = "Label", + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_POSITIVE_INTEGER").assertExists() @@ -46,6 +47,7 @@ class InputPositiveIntegerTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_POSITIVE_INTEGER").assertExists() @@ -77,6 +79,7 @@ class InputPositiveIntegerTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_POSITIVE_INTEGER").assertExists() @@ -98,6 +101,7 @@ class InputPositiveIntegerTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_POSITIVE_INTEGER").assertExists() @@ -114,6 +118,7 @@ class InputPositiveIntegerTest { title = "Label", inputText = "", legendData = LegendData(SurfaceColor.CustomGreen, "Legend"), + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_POSITIVE_INTEGER").assertExists() @@ -128,6 +133,7 @@ class InputPositiveIntegerTest { title = "Label", inputText = "", supportingText = listOf(SupportingTextData("Supporting text", SupportingTextState.DEFAULT)), + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_POSITIVE_INTEGER").assertExists() @@ -146,6 +152,7 @@ class InputPositiveIntegerTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_POSITIVE_INTEGER").assertExists() @@ -165,6 +172,7 @@ class InputPositiveIntegerTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_POSITIVE_INTEGER").assertExists() @@ -184,6 +192,7 @@ class InputPositiveIntegerTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_POSITIVE_INTEGER").assertExists() diff --git a/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputQRCodeTest.kt b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputQRCodeTest.kt index 9d0c655d2..ae5084e14 100644 --- a/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputQRCodeTest.kt +++ b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputQRCodeTest.kt @@ -33,6 +33,7 @@ class InputQRCodeTest { onQRButtonClicked = { // no-op }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_QR_CODE").assertExists() @@ -54,6 +55,7 @@ class InputQRCodeTest { onQRButtonClicked = { // no-op }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_QR_CODE").assertExists() @@ -79,6 +81,7 @@ class InputQRCodeTest { onQRButtonClicked = { // no-op }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_QR_CODE").assertExists() diff --git a/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputRadioButtonTest.kt b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputRadioButtonTest.kt index 8e8164115..095cabc62 100644 --- a/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputRadioButtonTest.kt +++ b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputRadioButtonTest.kt @@ -40,6 +40,7 @@ class InputRadioButtonTest { onItemChange = { selectedItem = it }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("RADIO_BUTTON_INPUT").assertExists() @@ -66,6 +67,7 @@ class InputRadioButtonTest { onItemChange = { selectedItem = it }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("RADIO_BUTTON_INPUT").assertExists() @@ -119,6 +121,7 @@ class InputRadioButtonTest { onItemChange = { selectedItem = it }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("RADIO_BUTTON_INPUT").assertExists() @@ -143,6 +146,7 @@ class InputRadioButtonTest { onItemChange = { selectedItem = it }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("RADIO_BUTTON_INPUT").assertExists() @@ -194,6 +198,7 @@ class InputRadioButtonTest { onItemChange = { selectedItem = it }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("RADIO_BUTTON_INPUT").assertExists() @@ -216,6 +221,7 @@ class InputRadioButtonTest { radioButtonData = radioButtonData, legendData = LegendData(SurfaceColor.CustomGreen, "Legend"), onItemChange = {}, + state = InputShellState.UNFOCUSED, ) } @@ -237,6 +243,7 @@ class InputRadioButtonTest { radioButtonData = radioButtonData, supportingText = listOf(SupportingTextData("Supporting text", SupportingTextState.DEFAULT)), onItemChange = {}, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("RADIO_BUTTON_INPUT").assertExists() diff --git a/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputTextTest.kt b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputTextTest.kt index aea27a9cc..96b70ae2f 100644 --- a/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputTextTest.kt +++ b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputTextTest.kt @@ -30,6 +30,7 @@ class InputTextTest { InputText( title = "Label", modifier = Modifier.testTag("INPUT_TEXT"), + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_TEXT").assertExists() @@ -50,6 +51,7 @@ class InputTextTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_TEXT").assertExists() @@ -83,6 +85,7 @@ class InputTextTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_TEXT").assertExists() @@ -105,6 +108,7 @@ class InputTextTest { inputValue = it } }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_TEXT").assertExists() @@ -122,6 +126,7 @@ class InputTextTest { modifier = Modifier.testTag("INPUT_TEXT"), inputText = "Input", legendData = LegendData(SurfaceColor.CustomGreen, "Legend"), + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_TEXT").assertExists() @@ -137,6 +142,7 @@ class InputTextTest { modifier = Modifier.testTag("INPUT_TEXT"), inputText = "Input", supportingText = listOf(SupportingTextData("Supporting text", SupportingTextState.DEFAULT)), + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_TEXT").assertExists() diff --git a/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputYesNoFieldTest.kt b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputYesNoFieldTest.kt index 3cf0641f2..365d99d72 100644 --- a/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputYesNoFieldTest.kt +++ b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputYesNoFieldTest.kt @@ -34,6 +34,7 @@ class InputYesNoFieldTest { onItemChange = { selectedItem = it }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_YES_NO_FIELD").assertExists() @@ -54,6 +55,7 @@ class InputYesNoFieldTest { onItemChange = { selectedItem = it }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_YES_NO_FIELD").assertExists() @@ -95,6 +97,7 @@ class InputYesNoFieldTest { onItemChange = { selectedItem = it }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_YES_NO_FIELD").assertExists() @@ -109,6 +112,7 @@ class InputYesNoFieldTest { modifier = Modifier.testTag("INPUT_YES_NO_FIELD"), onItemChange = { }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_YES_NO_FIELD").assertExists() @@ -148,6 +152,7 @@ class InputYesNoFieldTest { onItemChange = { selectedItem = it }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_YES_NO_FIELD").assertExists() @@ -164,6 +169,7 @@ class InputYesNoFieldTest { title = "Label", legendData = LegendData(SurfaceColor.CustomGreen, "Legend"), onItemChange = {}, + state = InputShellState.UNFOCUSED, ) } @@ -179,6 +185,7 @@ class InputYesNoFieldTest { title = "Label", supportingText = listOf(SupportingTextData("Supporting text", SupportingTextState.DEFAULT)), onItemChange = {}, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_YES_NO_FIELD").assertExists() diff --git a/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputYesOnlyCheckBoxTest.kt b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputYesOnlyCheckBoxTest.kt index dbafe49f1..679d3dcf5 100644 --- a/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputYesOnlyCheckBoxTest.kt +++ b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputYesOnlyCheckBoxTest.kt @@ -27,7 +27,7 @@ class InputYesOnlyCheckBoxTest { @Test fun shouldDisplayInputYesOnlyCheckBoxCorrectly() { rule.setContent { - var checkboxData by rememberSaveable { + val checkboxData by rememberSaveable { mutableStateOf(CheckBoxData(uid = "0", checked = false, enabled = true, textInput = "Label")) } InputYesOnlyCheckBox( @@ -35,6 +35,7 @@ class InputYesOnlyCheckBoxTest { modifier = Modifier.testTag("INPUT_YES_ONLY_CHECKBOX"), onClick = { }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_YES_ONLY_CHECKBOX").assertExists() @@ -54,6 +55,7 @@ class InputYesOnlyCheckBoxTest { onClick = { checkboxData = checkboxData.copy(checked = !checkboxData.checked) }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_YES_ONLY_CHECKBOX").assertExists() @@ -95,6 +97,7 @@ class InputYesOnlyCheckBoxTest { onClick = { checkboxData = checkboxData.copy(enabled = !checkboxData.enabled) }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_YES_ONLY_CHECKBOX").assertExists() @@ -114,6 +117,7 @@ class InputYesOnlyCheckBoxTest { onClick = { checkboxData = checkboxData.copy(enabled = !checkboxData.enabled) }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_YES_ONLY_CHECKBOX").assertExists() diff --git a/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputYesOnlySwitchTest.kt b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputYesOnlySwitchTest.kt index 6350700fe..a32d4a1f1 100644 --- a/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputYesOnlySwitchTest.kt +++ b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputYesOnlySwitchTest.kt @@ -34,6 +34,7 @@ class InputYesOnlySwitchTest { onClick = { selectedItem = it }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_YES_ONLY_SWITCH").assertExists() @@ -54,6 +55,7 @@ class InputYesOnlySwitchTest { onClick = { selectedItem = it }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_YES_ONLY_SWITCH").assertExists() @@ -94,6 +96,7 @@ class InputYesOnlySwitchTest { onClick = { selectedItem = it }, + state = InputShellState.UNFOCUSED, ) } @@ -115,6 +118,7 @@ class InputYesOnlySwitchTest { onClick = { selectedItem = it }, + state = InputShellState.UNFOCUSED, ) } rule.onNodeWithTag("INPUT_YES_ONLY_SWITCH").assertExists() From dd42d28d3a51ffd28f05f29f7a7a9edad5b6eb77 Mon Sep 17 00:00:00 2001 From: Sasikanth Miriyampalli Date: Tue, 10 Oct 2023 16:07:34 +0530 Subject: [PATCH 4/4] Add `InputAge` component (#96) --- .../dhis/common/screens/InputAgeScreen.kt | 86 ++++++- .../designsystem/component/AgeFieldHelper.kt | 14 +- .../ui/designsystem/component/InputAge.kt | 226 ++++++++++++++++++ .../ui/designsystem/component/InputField.kt | 18 +- .../component/internal/StringUtils.kt | 56 +++++ .../ui/designsystem/component/InputAgeTest.kt | 144 +++++++++++ .../internal/DateOfBirthTransformationTest.kt | 41 ++++ 7 files changed, 576 insertions(+), 9 deletions(-) create mode 100644 designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputAge.kt create mode 100644 designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputAgeTest.kt create mode 100644 designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/internal/DateOfBirthTransformationTest.kt diff --git a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputAgeScreen.kt b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputAgeScreen.kt index 0b9b6aa6d..f55210902 100644 --- a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputAgeScreen.kt +++ b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/InputAgeScreen.kt @@ -5,7 +5,10 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue +import org.hisp.dhis.mobile.ui.designsystem.component.AgeInputType import org.hisp.dhis.mobile.ui.designsystem.component.ColumnComponentContainer +import org.hisp.dhis.mobile.ui.designsystem.component.InputAge +import org.hisp.dhis.mobile.ui.designsystem.component.InputShellState import org.hisp.dhis.mobile.ui.designsystem.component.Orientation import org.hisp.dhis.mobile.ui.designsystem.component.RadioButtonData import org.hisp.dhis.mobile.ui.designsystem.component.SubTitle @@ -14,7 +17,7 @@ import org.hisp.dhis.mobile.ui.designsystem.component.TimeUnitValues @Composable fun InputAgeScreen() { - ColumnComponentContainer("Age Field components") { + ColumnComponentContainer { SubTitle("Horizontal Age Field Helper") var selectedFieldHorizontal by remember { mutableStateOf(RadioButtonData("0", selected = true, enabled = true, textInput = TimeUnitValues.YEARS.value)) @@ -22,5 +25,86 @@ fun InputAgeScreen() { TimeUnitSelector(Orientation.HORIZONTAL, TimeUnitValues.YEARS.value) { selectedFieldHorizontal = it } + + SubTitle("Input Age Component - Idle") + var inputType by remember { mutableStateOf(AgeInputType.None) } + + InputAge( + title = "Label", + inputType = inputType, + onCalendarActionClicked = { + // no-op + }, + onValueChanged = { newInputType -> + inputType = newInputType + }, + ) + + SubTitle("Input Age Component - Idle Disabled") + InputAge( + title = "Label", + inputType = AgeInputType.None, + state = InputShellState.DISABLED, + onCalendarActionClicked = { + // no-op + }, + onValueChanged = { newInputType -> + inputType = newInputType + }, + ) + + SubTitle("Input Age Component - Date Of Birth") + InputAge( + title = "Label", + inputType = AgeInputType.DateOfBirth("01011985"), + state = InputShellState.DISABLED, + onCalendarActionClicked = { + // no-op + }, + onValueChanged = { newInputType -> + inputType = newInputType + }, + ) + + SubTitle("Input Age Component - Date Of Birth Required Error") + InputAge( + title = "Label", + inputType = AgeInputType.DateOfBirth("010"), + state = InputShellState.ERROR, + isRequired = true, + onCalendarActionClicked = { + // no-op + }, + onValueChanged = { + // no-op + }, + ) + + SubTitle("Input Age Component - Age Disabled") + InputAge( + title = "Label", + inputType = AgeInputType.Age(value = "56", unit = TimeUnitValues.YEARS), + state = InputShellState.DISABLED, + onCalendarActionClicked = { + // no-op + }, + onValueChanged = { newInputType -> + inputType = newInputType + }, + ) + + SubTitle("Input Age Component - Age Required Error") + InputAge( + title = "Label", + inputType = AgeInputType.Age(value = "56", unit = TimeUnitValues.YEARS), + state = InputShellState.ERROR, + isRequired = true, + onCalendarActionClicked = { + // no-op + }, + onValueChanged = { + // no-op + }, + ) } } diff --git a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/AgeFieldHelper.kt b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/AgeFieldHelper.kt index 5daf918a1..704c2ff37 100644 --- a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/AgeFieldHelper.kt +++ b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/AgeFieldHelper.kt @@ -25,18 +25,26 @@ import org.hisp.dhis.mobile.ui.designsystem.theme.SurfaceColor fun TimeUnitSelector( orientation: Orientation, optionSelected: String, + modifier: Modifier = Modifier, + enabled: Boolean = true, onClick: (RadioButtonData) -> Unit, ) { + val backgroundColor = if (enabled) { + SurfaceColor.Surface + } else { + SurfaceColor.DisabledSurface + } + RowComponentContainer( - modifier = Modifier - .background(color = SurfaceColor.Surface, Shape.SmallBottom) + modifier = modifier + .background(color = backgroundColor, Shape.SmallBottom) .padding( start = Spacing.Spacing8, end = Spacing.Spacing8, ), ) { val options = TimeUnitValues.values().map { - RadioButtonData(it.value, optionSelected == it.value, true, provideStringResource(it.value)) + RadioButtonData(it.value, optionSelected == it.value, enabled, provideStringResource(it.value)) } val selectedItem = options.find { it.selected diff --git a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputAge.kt b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputAge.kt new file mode 100644 index 000000000..15dab7ab8 --- /dev/null +++ b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputAge.kt @@ -0,0 +1,226 @@ +package org.hisp.dhis.mobile.ui.designsystem.component + +import androidx.compose.foundation.focusable +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Event +import androidx.compose.material.icons.outlined.Cancel +import androidx.compose.material3.Icon +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.input.KeyboardType +import org.hisp.dhis.mobile.ui.designsystem.component.AgeInputType.Age +import org.hisp.dhis.mobile.ui.designsystem.component.AgeInputType.DateOfBirth +import org.hisp.dhis.mobile.ui.designsystem.component.AgeInputType.None +import org.hisp.dhis.mobile.ui.designsystem.component.TimeUnitValues.YEARS +import org.hisp.dhis.mobile.ui.designsystem.component.internal.RegExValidations +import org.hisp.dhis.mobile.ui.designsystem.resource.provideStringResource +import org.hisp.dhis.mobile.ui.designsystem.theme.Spacing + +// Update [DateOfBirthTransformation] when updating the mask +// Check the usages before modifying +private const val DATE_OF_BIRTH_MASK = "DDMMYYYY" + +/** + * Input filed to enter date-of-birth or age + * + * @param title: Label of the component. + * @param inputType: The type of input : + * [None] : default, + * [DateOfBirth] : In ddmmyyyy format, + * [Age]: Age value with appropriate time unit + * @param onCalendarActionClicked: Callback to handle the action when the calendar icon is clicked. + * @param state: [InputShellState] + * @param supportingText: List of [SupportingTextData] that manages all the messages to be shown. + * @param isRequired: Mark this input as marked + * @param onValueChanged: Callback to receive changes in the input + */ +@Composable +fun InputAge( + title: String, + inputType: AgeInputType = None, + onCalendarActionClicked: () -> Unit, + modifier: Modifier = Modifier, + state: InputShellState = InputShellState.UNFOCUSED, + supportingText: List? = null, + isRequired: Boolean = false, + imeAction: ImeAction = ImeAction.Next, + dateOfBirthLabel: String = provideStringResource("date_birth"), + orLabel: String = provideStringResource("or"), + ageLabel: String = provideStringResource("age"), + onFocusChanged: ((Boolean) -> Unit) = {}, + onValueChanged: (AgeInputType) -> Unit, +) { + val maxAgeCharLimit = 3 + val allowedCharacters = RegExValidations.DATE_OF_BIRTH.regex + + val helperText = remember(inputType) { + when (inputType) { + None -> null + is DateOfBirth -> DATE_OF_BIRTH_MASK + is Age -> inputType.unit.value + } + } + val helperStyle = remember(inputType) { + when (inputType) { + None -> InputStyle.NONE + is DateOfBirth -> InputStyle.WITH_DATE_OF_BIRTH_HELPER + is Age -> InputStyle.WITH_HELPER_AFTER + } + } + + val calendarButton: (@Composable () -> Unit)? = if (inputType is DateOfBirth) { + @Composable { + SquareIconButton( + modifier = Modifier.testTag("INPUT_AGE_OPEN_CALENDAR_BUTTON"), + icon = { + Icon( + imageVector = Icons.Filled.Event, + contentDescription = null, + ) + }, + onClick = onCalendarActionClicked, + enabled = state != InputShellState.DISABLED, + ) + } + } else { + null + } + + InputShell( + modifier = modifier.testTag("INPUT_AGE"), + title = title, + state = state, + isRequiredField = isRequired, + onFocusChanged = onFocusChanged, + inputField = { + when (inputType) { + None -> { + TextButtonSelector( + modifier = Modifier.focusable(true) + .testTag("INPUT_AGE_MODE_SELECTOR"), + firstOptionText = dateOfBirthLabel, + onClickFirstOption = { + onValueChanged.invoke(DateOfBirth.EMPTY) + }, + middleText = orLabel, + secondOptionText = ageLabel, + onClickSecondOption = { + onValueChanged.invoke(Age.EMPTY) + }, + enabled = state != InputShellState.DISABLED, + ) + } + is DateOfBirth, is Age -> { + BasicTextField( + modifier = Modifier + .testTag("INPUT_AGE_TEXT_FIELD") + .fillMaxWidth(), + inputText = transformInputText(inputType), + helper = helperText, + isSingleLine = true, + helperStyle = helperStyle, + onInputChanged = { newText -> + if (newText.length > maxAgeCharLimit && inputType is Age) { + return@BasicTextField + } + + @Suppress("KotlinConstantConditions") + val newInputType: AgeInputType = when (inputType) { + is Age -> inputType.copy(value = newText) + is DateOfBirth -> updateDateOfBirth(inputType, newText) + None -> None + } + + if (allowedCharacters.containsMatchIn(newText) || newText.isBlank()) { + onValueChanged.invoke(newInputType) + } + }, + enabled = state != InputShellState.DISABLED, + state = state, + keyboardOptions = KeyboardOptions(imeAction = imeAction, keyboardType = KeyboardType.Number), + ) + } + } + }, + primaryButton = { + if (inputType != None && state != InputShellState.DISABLED) { + IconButton( + modifier = Modifier.testTag("INPUT_AGE_RESET_BUTTON").padding(Spacing.Spacing0), + icon = { + Icon( + imageVector = Icons.Outlined.Cancel, + contentDescription = "Icon Button", + ) + }, + onClick = { + onValueChanged.invoke(None) + }, + ) + } + }, + secondaryButton = calendarButton, + supportingText = { + supportingText?.forEach { label -> + SupportingText( + label.text, + label.state, + ) + } + }, + legend = { + if (inputType is Age) { + TimeUnitSelector( + modifier = Modifier.fillMaxWidth() + .testTag("INPUT_AGE_TIME_UNIT_SELECTOR"), + orientation = Orientation.HORIZONTAL, + optionSelected = YEARS.value, + enabled = state != InputShellState.DISABLED, + onClick = { itemData -> + val timeUnit = TimeUnitValues.entries + .first { it.value.contains(itemData.textInput!!, ignoreCase = true) } + + onValueChanged.invoke(inputType.copy(unit = timeUnit)) + }, + ) + } + }, + ) +} + +private fun transformInputText(inputType: AgeInputType): String { + return when (inputType) { + is Age -> inputType.value + is DateOfBirth -> inputType.value + None -> "" + } +} + +private fun updateDateOfBirth(inputType: DateOfBirth, newText: String): AgeInputType { + return if (newText.length <= DATE_OF_BIRTH_MASK.length) { + inputType.copy(value = newText) + } else { + inputType + } +} + +sealed interface AgeInputType { + data object None : AgeInputType + + data class DateOfBirth(val value: String) : AgeInputType { + companion object { + val EMPTY = DateOfBirth("") + } + } + + data class Age(val value: String, val unit: TimeUnitValues) : AgeInputType { + companion object { + val EMPTY = Age("", YEARS) + } + } +} diff --git a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputField.kt b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputField.kt index 3449dad06..c575a1bd6 100644 --- a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputField.kt +++ b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputField.kt @@ -28,6 +28,7 @@ import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.VisualTransformation +import org.hisp.dhis.mobile.ui.designsystem.component.internal.DateOfBirthTransformation import org.hisp.dhis.mobile.ui.designsystem.component.internal.PrefixTransformation import org.hisp.dhis.mobile.ui.designsystem.component.internal.SuffixTransformer import org.hisp.dhis.mobile.ui.designsystem.theme.Color.Blue300 @@ -91,11 +92,17 @@ fun BasicTextField( var visualTransformation = VisualTransformation.None if (helperStyle != InputStyle.NONE) { - if (helperStyle == InputStyle.WITH_HELPER_BEFORE) { - helper?.let { visualTransformation = PrefixTransformation(it, enabled) } - } else { - helper?.let { - visualTransformation = SuffixTransformer(it) + when (helperStyle) { + InputStyle.WITH_HELPER_BEFORE -> { + helper?.let { visualTransformation = PrefixTransformation(it, enabled) } + } + InputStyle.WITH_DATE_OF_BIRTH_HELPER -> { + helper?.let { visualTransformation = DateOfBirthTransformation(it) } + } + else -> { + helper?.let { + visualTransformation = SuffixTransformer(it) + } } } } @@ -153,5 +160,6 @@ fun BasicTextField( enum class InputStyle { WITH_HELPER_AFTER, WITH_HELPER_BEFORE, + WITH_DATE_OF_BIRTH_HELPER, NONE, } diff --git a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/internal/StringUtils.kt b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/internal/StringUtils.kt index cdea45c03..8e803781d 100644 --- a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/internal/StringUtils.kt +++ b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/internal/StringUtils.kt @@ -1,6 +1,7 @@ package org.hisp.dhis.mobile.ui.designsystem.component.internal import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.input.OffsetMapping import androidx.compose.ui.text.input.TransformedText import androidx.compose.ui.text.input.VisualTransformation @@ -62,6 +63,60 @@ internal class SuffixTransformer(val suffix: String) : VisualTransformation { } } +internal class DateOfBirthTransformation(private val mask: String) : VisualTransformation { + + companion object { + private const val SEPARATOR = "/" + } + + override fun filter(text: AnnotatedString): TransformedText { + return dateFilter(text) + } + + private fun dateFilter(text: AnnotatedString): TransformedText { + val trimmed = if (text.text.length > mask.length) text.text.substring(0..mask.length) else text.text + val output = buildAnnotatedString { + for (i in mask.indices) { + val dateChar = trimmed.getOrNull(i) + if (dateChar == null) { + append(AnnotatedString(mask[i].toString(), DHIS2SCustomTextStyles.inputFieldHelper)) + } else { + append(trimmed[i]) + } + + if (i % 2 == 1 && i < 4) { + val separator = if (dateChar != null) { + SEPARATOR + } else { + AnnotatedString(SEPARATOR, DHIS2SCustomTextStyles.inputFieldHelper) + } + append(separator) + } + } + } + + val offsetMapping = object : OffsetMapping { + override fun originalToTransformed(offset: Int): Int { + if (trimmed.lastIndex >= 0) { + if (offset <= 1) return offset + if (offset <= 3) return offset + 1 + if (offset <= 8) return offset + 2 + return 10 + } else { + return 0 + } + } + + override fun transformedToOriginal(offset: Int): Int { + if (offset > text.length) return text.length + return offset + } + } + + return TransformedText(output, offsetMapping) + } +} + enum class RegExValidations(val regex: Regex) { BRITISH_DECIMAL_NOTATION("""^(?!\.)(?!.*-[^0-9])(?!(?:[^.]*\.){3})[-0-9]*(?:\.[0-9]*)?$""".toRegex()), EUROPEAN_DECIMAL_NOTATION("""^(?!.*,.+,|.*-.*-)[0-9,-]*$""".toRegex()), @@ -74,4 +129,5 @@ enum class RegExValidations(val regex: Regex) { PHONE_NUMBER("^[+0-9-()]+$".toRegex()), LINK("((https?|ftp|smtp)://)?(www\\.)?[a-zA-Z0-9@:%._+~#=-]{2,256}\\.[a-z]{2,6}\\b([-a-zA-Z0-9@:%_+.~#?&/=-]*)".toRegex()), EMAIL("^[a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,6}\$".toRegex()), + DATE_OF_BIRTH("^[0-9]+$".toRegex()), } diff --git a/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputAgeTest.kt b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputAgeTest.kt new file mode 100644 index 000000000..c7ffc5ccf --- /dev/null +++ b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputAgeTest.kt @@ -0,0 +1,144 @@ +package org.hisp.dhis.mobile.ui.designsystem.component + +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +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.junit.Rule +import org.junit.Test + +class InputAgeTest { + + @get:Rule + val rule = createComposeRule() + + @Test + fun modeSelectionShouldBeShownWhenComponentIsInitialised() { + rule.setContent { + InputAge( + title = "Label", + onCalendarActionClicked = { + // no-op + }, + ) { + // no-op + } + } + + rule.onNodeWithTag("INPUT_AGE_MODE_SELECTOR").assertExists() + rule.onNodeWithTag("INPUT_AGE_TEXT_FIELD").assertDoesNotExist() + rule.onNodeWithTag("INPUT_AGE_RESET_BUTTON").assertDoesNotExist() + rule.onNodeWithTag("INPUT_AGE_OPEN_CALENDAR_BUTTON").assertDoesNotExist() + rule.onNodeWithTag("INPUT_AGE_TIME_UNIT_SELECTOR").assertDoesNotExist() + } + + @Test + fun dateOfBirthFieldShouldBeShownCorrectly() { + rule.setContent { + InputAge( + title = "Label", + inputType = AgeInputType.DateOfBirth.EMPTY, + onCalendarActionClicked = { + // no-op + }, + ) { + // no-op + } + } + + rule.onNodeWithTag("INPUT_AGE_MODE_SELECTOR").assertDoesNotExist() + rule.onNodeWithTag("INPUT_AGE_TEXT_FIELD").assertExists() + rule.onNodeWithTag("INPUT_AGE_RESET_BUTTON").assertExists() + rule.onNodeWithTag("INPUT_AGE_OPEN_CALENDAR_BUTTON").assertExists() + rule.onNodeWithTag("INPUT_AGE_TIME_UNIT_SELECTOR").assertDoesNotExist() + } + + @Test + fun dateOfBirthFieldChangesShouldWorkCorrectly() { + var inputType by mutableStateOf(AgeInputType.None) + rule.setContent { + InputAge( + title = "Label", + inputType = AgeInputType.DateOfBirth.EMPTY, + onCalendarActionClicked = { + // no-op + }, + ) { + inputType = it + } + } + + rule.onNodeWithTag("INPUT_AGE_TEXT_FIELD").performTextInput("1002") + + assert(inputType == AgeInputType.DateOfBirth("1002")) + } + + @Test + fun ageFieldShouldBeShownCorrectly() { + rule.setContent { + InputAge( + title = "Label", + inputType = AgeInputType.Age.EMPTY, + onCalendarActionClicked = { + // no-op + }, + ) { + // no-op + } + } + + rule.onNodeWithTag("INPUT_AGE_MODE_SELECTOR").assertDoesNotExist() + rule.onNodeWithTag("INPUT_AGE_TEXT_FIELD").assertExists() + rule.onNodeWithTag("INPUT_AGE_RESET_BUTTON").assertExists() + rule.onNodeWithTag("INPUT_AGE_OPEN_CALENDAR_BUTTON").assertDoesNotExist() + rule.onNodeWithTag("INPUT_AGE_TIME_UNIT_SELECTOR").assertExists() + } + + @Test + fun ageFieldChangesShouldWorkCorrectly() { + var inputType by mutableStateOf(AgeInputType.None) + rule.setContent { + InputAge( + title = "Label", + inputType = AgeInputType.Age.EMPTY, + onCalendarActionClicked = { + // no-op + }, + ) { + inputType = it + } + } + + rule.onNodeWithTag("INPUT_AGE_TEXT_FIELD").performTextInput("56") + + assert(inputType == AgeInputType.Age(value = "56", unit = TimeUnitValues.YEARS)) + } + + @Test + fun clickingOnRestButtonShouldResetMode() { + var inputType by mutableStateOf(AgeInputType.Age.EMPTY) + + rule.setContent { + InputAge( + title = "Label", + inputType = inputType, + onCalendarActionClicked = { + // no-op + }, + ) { + inputType = it + } + } + + rule.onNodeWithTag("INPUT_AGE_RESET_BUTTON").performClick() + + rule.onNodeWithTag("INPUT_AGE_MODE_SELECTOR").assertExists() + rule.onNodeWithTag("INPUT_AGE_TEXT_FIELD").assertDoesNotExist() + rule.onNodeWithTag("INPUT_AGE_RESET_BUTTON").assertDoesNotExist() + rule.onNodeWithTag("INPUT_AGE_OPEN_CALENDAR_BUTTON").assertDoesNotExist() + rule.onNodeWithTag("INPUT_AGE_TIME_UNIT_SELECTOR").assertDoesNotExist() + } +} diff --git a/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/internal/DateOfBirthTransformationTest.kt b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/internal/DateOfBirthTransformationTest.kt new file mode 100644 index 000000000..eb0844d3d --- /dev/null +++ b/designsystem/src/desktopTest/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/internal/DateOfBirthTransformationTest.kt @@ -0,0 +1,41 @@ +package org.hisp.dhis.mobile.ui.designsystem.component.internal + +import androidx.compose.ui.text.AnnotatedString +import org.junit.Test + +private const val DATE_OF_BIRTH_MASK = "DDMMYYYY" + +class DateOfBirthTransformationTest { + + private val transformation = DateOfBirthTransformation(DATE_OF_BIRTH_MASK) + + @Test + fun dateOfBirthTransformationShouldWorkCorrectly() { + val transformedText = transformation + .filter(AnnotatedString("10041985")) + .text + .toString() + + assert(transformedText == "10/04/1985") + } + + @Test + fun partialDateOfBirthTransformationShouldWorkCorrectly() { + val transformedText = transformation + .filter(AnnotatedString("100")) + .text + .toString() + + assert(transformedText == "10/0M/YYYY") + } + + @Test + fun emptyTextShouldDisplayDateOfBirthMask() { + val transformedText = transformation + .filter(AnnotatedString("")) + .text + .toString() + + assert(transformedText == "DD/MM/YYYY") + } +}