Skip to content

Commit

Permalink
refactor input fields
Browse files Browse the repository at this point in the history
  • Loading branch information
xavimolloy committed Sep 12, 2023
1 parent 8fae298 commit 0669db1
Show file tree
Hide file tree
Showing 14 changed files with 265 additions and 685 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package org.hisp.dhis.common.screens

import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.BookmarkBorder
import androidx.compose.material.icons.outlined.HelpOutline
Expand Down Expand Up @@ -33,6 +35,8 @@ fun BottomSheetHeaderScreen() {
},
)
}
Spacer(Modifier.size(Spacing.Spacing12))

SubTitle("Without Icon", TextColor.OnSurface)

Box(modifier = Modifier.border(Spacing.Spacing1, color = TextColor.OnDisabledSurface)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ 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.DecimalNotation
import org.hisp.dhis.mobile.ui.designsystem.component.Description
import org.hisp.dhis.mobile.ui.designsystem.component.InputNumber
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.Title
import org.hisp.dhis.mobile.ui.designsystem.component.internal.RegExValidations
import org.hisp.dhis.mobile.ui.designsystem.theme.Spacing
import org.hisp.dhis.mobile.ui.designsystem.theme.TextColor

Expand All @@ -33,7 +33,7 @@ fun InputNumberScreen() {
inputValue1 = it
}
},
notation = DecimalNotation.BRITISH,
notation = RegExValidations.BRITISH_DECIMAL_NOTATION,
)
Spacer(Modifier.size(Spacing.Spacing8))

Expand All @@ -48,7 +48,7 @@ fun InputNumberScreen() {
inputValueEuropean = it
}
},
notation = DecimalNotation.EUROPEAN,
notation = RegExValidations.EUROPEAN_DECIMAL_NOTATION,
)
Spacer(Modifier.size(Spacing.Spacing8))

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
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.Cancel
import androidx.compose.material3.Icon
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusDirection
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.testTag
import org.hisp.dhis.mobile.ui.designsystem.component.internal.RegExValidations
import java.util.Locale

/**
* DHIS2 Input positive Integer. Wraps DHIS · [InputShell].
* Only positive integers allowed, excluding 0
* @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 modifier allows a modifier to be passed externally
*/
@Composable
internal fun GenericInput(
title: String,
state: InputShellState = InputShellState.UNFOCUSED,
supportingText: List<SupportingTextData>? = null,
legendData: LegendData? = null,
inputText: String? = null,
isRequiredField: Boolean = false,
onNextClicked: (() -> Unit)? = null,
onValueChanged: ((String?) -> Unit)? = null,
keyboardOptions: KeyboardOptions,
allowedCharacters: Regex? = null,
helper: String? = null,
helperStyle: InputStyle = InputStyle.NONE,
testTag: String = "",
isSingleLine: Boolean = true,
modifier: Modifier = Modifier,
) {
val inputValue by remember(inputText) { mutableStateOf(inputText) }

var deleteButtonIsVisible by remember { mutableStateOf(!inputText.isNullOrEmpty() && state != InputShellState.DISABLED) }
val focusManager = LocalFocusManager.current
InputShell(
modifier = modifier.testTag("INPUT_$testTag"),
isRequiredField = isRequiredField,
title = title,
primaryButton = {
if (deleteButtonIsVisible) {
IconButton(
modifier = Modifier.testTag("INPUT_" + testTag + "_RESET_BUTTON"),
icon = {
Icon(
imageVector = Icons.Outlined.Cancel,
contentDescription = "Icon Button",
)
},
onClick = {
onValueChanged?.invoke("")
deleteButtonIsVisible = false
},
enabled = state != InputShellState.DISABLED,
)
}
},
state = state,
legend = {
legendData?.let {
Legend(legendData, Modifier.testTag("INPUT_" + testTag + "_LEGEND"))
}
},
supportingText = {
supportingText?.forEach {
label ->
SupportingText(
label.text,
label.state,
modifier = Modifier.testTag("INPUT_" + testTag + "_SUPPORTING_TEXT"),
)
}
},
inputField = {
BasicInput(
modifier = Modifier.testTag("INPUT_" + testTag + "_FIELD"),
inputText = inputValue ?: "",
helper = helper,
isSingleLine = isSingleLine,
helperStyle = helperStyle,
onInputChanged = {
if (allowedCharacters != null) {
if (allowedCharacters == RegExValidations.SINGLE_LETTER.regex) {
if (it.uppercase(Locale.getDefault()).matches(allowedCharacters) || it.isEmpty()) {
onValueChanged?.invoke(it.uppercase(Locale.getDefault()))
deleteButtonIsVisible = it.isNotEmpty()
}
} else {
if (it.matches(allowedCharacters) || it.isEmpty()) {
onValueChanged?.invoke(it)
deleteButtonIsVisible = it.isNotEmpty()
}
}
} else {
onValueChanged?.invoke(it)
deleteButtonIsVisible = it.isNotEmpty()
}
},
enabled = state != InputShellState.DISABLED,
state = state,
keyboardOptions = keyboardOptions,
onNextClicked = {
if (onNextClicked != null) {
onNextClicked.invoke()
} else {
focusManager.moveFocus(FocusDirection.Down)
}
},
)
},
)
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,11 @@
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.Cancel
import androidx.compose.material3.Icon
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusDirection
import androidx.compose.ui.platform.LocalFocusManager
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

/**
* DHIS2 Input Integer. Wraps DHIS · [InputShell].
Expand Down Expand Up @@ -44,71 +35,18 @@ fun InputInteger(
imeAction: ImeAction = ImeAction.Next,
modifier: Modifier = Modifier,
) {
val inputValue by remember(inputText) { mutableStateOf(inputText) }

var deleteButtonIsVisible by remember { mutableStateOf(!inputText.isNullOrEmpty() && state != InputShellState.DISABLED) }
val focusManager = LocalFocusManager.current
val pattern = remember { Regex("^-?(?!0)\\d*") }
val keyboardOptions = KeyboardOptions(imeAction = imeAction, keyboardType = KeyboardType.Number)
InputShell(
modifier = modifier.testTag("INPUT_INTEGER"),
isRequiredField = isRequiredField,
GenericInput(
title = title,
primaryButton = {
if (deleteButtonIsVisible) {
IconButton(
modifier = Modifier.testTag("INPUT_INTEGER_RESET_BUTTON"),
icon = {
Icon(
imageVector = Icons.Outlined.Cancel,
contentDescription = "Icon Button",
)
},
onClick = {
onValueChanged?.invoke("")
deleteButtonIsVisible = false
},
enabled = state != InputShellState.DISABLED,
)
}
},
state = state,
legend = {
legendData?.let {
Legend(legendData, Modifier.testTag("INPUT_INTEGER_LEGEND"))
}
},
supportingText = {
supportingText?.forEach {
label ->
SupportingText(
label.text,
label.state,
modifier = Modifier.testTag("INPUT_INTEGER_SUPPORTING_TEXT"),
)
}
},
inputField = {
BasicInput(
modifier = Modifier.testTag("INPUT_INTEGER_FIELD"),
inputText = inputValue ?: "",
onInputChanged = {
if (it.matches(pattern) || it.isEmpty()) {
onValueChanged?.invoke(it)
deleteButtonIsVisible = it.isNotEmpty()
}
},
enabled = state != InputShellState.DISABLED,
state = state,
keyboardOptions = keyboardOptions,
onNextClicked = {
if (onNextClicked != null) {
onNextClicked.invoke()
} else {
focusManager.moveFocus(FocusDirection.Down)
}
},
)
},
supportingText = supportingText,
legendData = legendData,
inputText = inputText,
isRequiredField = isRequiredField,
onNextClicked = onNextClicked,
onValueChanged = onValueChanged,
keyboardOptions = KeyboardOptions(imeAction = imeAction, keyboardType = KeyboardType.Number),
allowedCharacters = RegExValidations.ONLY_INTEGERS.regex,
modifier = modifier,
testTag = "INTEGER",
)
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,12 @@
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.Cancel
import androidx.compose.material3.Icon
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusDirection
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardCapitalization
import java.util.Locale
import androidx.compose.ui.text.input.KeyboardType
import org.hisp.dhis.mobile.ui.designsystem.component.internal.RegExValidations

/**
* DHIS2 Input Letter. Wraps DHIS · [InputShell].
Expand All @@ -42,71 +33,22 @@ fun InputLetter(
imeAction: ImeAction = ImeAction.Next,
modifier: Modifier = Modifier,
) {
val inputValue by remember(inputText) { mutableStateOf(inputText) }

var deleteButtonIsVisible by remember { mutableStateOf(!inputText.isNullOrEmpty() && state != InputShellState.DISABLED) }
val focusManager = LocalFocusManager.current
val pattern = remember { Regex("^[A-Z]\$") }
val keyboardOptions = KeyboardOptions(imeAction = imeAction, capitalization = KeyboardCapitalization.Characters)
InputShell(
modifier = modifier,
isRequiredField = isRequiredField,
GenericInput(
title = title,
primaryButton = {
if (deleteButtonIsVisible) {
IconButton(
modifier = Modifier.testTag("INPUT_LETTER_RESET_BUTTON"),
icon = {
Icon(
imageVector = Icons.Outlined.Cancel,
contentDescription = "Icon Button",
)
},
onClick = {
onValueChanged?.invoke("")
deleteButtonIsVisible = false
},
enabled = state != InputShellState.DISABLED,
)
}
},
state = state,
legend = {
legendData?.let {
Legend(legendData, Modifier.testTag("INPUT_LETTER_LEGEND"))
}
},
supportingText = {
supportingText?.forEach {
label ->
SupportingText(
label.text,
label.state,
modifier = Modifier.testTag("INPUT_LETTER_SUPPORTING_TEXT"),
)
}
},
inputField = {
BasicInput(
modifier = Modifier.testTag("INPUT_LETTER_FIELD"),
inputText = inputValue ?: "",
onInputChanged = {
if (it.uppercase(Locale.getDefault()).matches(pattern) || it.isEmpty()) {
onValueChanged?.invoke(it.uppercase(Locale.getDefault()))
}
deleteButtonIsVisible = it.isNotEmpty()
},
enabled = state != InputShellState.DISABLED,
state = state,
keyboardOptions = keyboardOptions,
onNextClicked = {
if (onNextClicked != null) {
onNextClicked.invoke()
} else {
focusManager.moveFocus(FocusDirection.Down)
}
},
)
},
supportingText = supportingText,
legendData = legendData,
inputText = inputText,
isRequiredField = isRequiredField,
onNextClicked = onNextClicked,
onValueChanged = onValueChanged,
keyboardOptions = KeyboardOptions(
imeAction = imeAction,
keyboardType = KeyboardType.Text,
capitalization = KeyboardCapitalization.Characters,
),
allowedCharacters = RegExValidations.SINGLE_LETTER.regex,
modifier = modifier,
testTag = "LETTER",
)
}
Loading

0 comments on commit 0669db1

Please sign in to comment.