Skip to content

Commit

Permalink
ANDROAPP-5506-mobile-ui-Create-Input-Letter-component (#47)
Browse files Browse the repository at this point in the history
* Create component and implement functionality

* Implement tests for component

* Add error example and default values for SupportingText component

* ktlint style fix

* ktlint
  • Loading branch information
xavimolloy authored Sep 8, 2023
1 parent 9fa87fa commit 782861f
Show file tree
Hide file tree
Showing 6 changed files with 428 additions and 2 deletions.
4 changes: 3 additions & 1 deletion common/src/commonMain/kotlin/org/hisp/dhis/common/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import org.hisp.dhis.common.screens.FormShellsScreen
import org.hisp.dhis.common.screens.FormsComponentsScreen
import org.hisp.dhis.common.screens.IconButtonScreen
import org.hisp.dhis.common.screens.InputIntegerScreen
import org.hisp.dhis.common.screens.InputLetterScreen
import org.hisp.dhis.common.screens.InputLongTextScreen
import org.hisp.dhis.common.screens.InputNegativeIntegerScreen
import org.hisp.dhis.common.screens.InputNumberScreen
Expand All @@ -56,7 +57,7 @@ fun App() {

@Composable
fun Main() {
val currentScreen = remember { mutableStateOf(Components.INPUT_LONG_TEXT) }
val currentScreen = remember { mutableStateOf(Components.INPUT_LETTER) }
var expanded by remember { mutableStateOf(false) }

Column(
Expand Down Expand Up @@ -125,6 +126,7 @@ fun Main() {
Components.INPUT_NEGATIVE_INTEGER -> InputNegativeIntegerScreen()
Components.INPUT_INTEGER -> InputIntegerScreen()
Components.INPUT_NUMBER -> InputNumberScreen()
Components.INPUT_LETTER -> InputLetterScreen()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ enum class Components(val label: String) {
INPUT_POSITIVE_INTEGER("Input Positive Integer"),
INPUT_INTEGER("Input Integer"),
INPUT_NUMBER("Input Number"),
INPUT_LETTER("Input Letter"),
FORM_SHELLS("Form Shells"),
BOTTOM_SHEET("Bottom Sheet"),
TAGS("Tags"),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package org.hisp.dhis.common.screens

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.text.input.ImeAction
import org.hisp.dhis.mobile.ui.designsystem.component.ColumnComponentContainer
import org.hisp.dhis.mobile.ui.designsystem.component.InputLetter
import org.hisp.dhis.mobile.ui.designsystem.component.InputShellState
import org.hisp.dhis.mobile.ui.designsystem.component.LegendData
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.SurfaceColor
import org.hisp.dhis.mobile.ui.designsystem.theme.TextColor

@Composable
fun InputLetterScreen() {
ColumnComponentContainer {
Title("Input Letter component", textColor = TextColor.OnSurfaceVariant)
SubTitle(" Basic Input Letter", textColor = TextColor.OnSurfaceVariant)
var inputValue1 by rememberSaveable { mutableStateOf("") }

InputLetter(
title = "Label",
inputText = inputValue1,
onValueChanged = {
if (it != null) {
inputValue1 = it
}
},
)
SubTitle(" Basic Input Letter with erro", textColor = TextColor.OnSurfaceVariant)
var inputValueError by rememberSaveable { mutableStateOf("") }

InputLetter(
title = "Label",
inputText = inputValueError,
onValueChanged = {
if (it != null) {
inputValueError = it
}
},
supportingText = listOf(SupportingTextData("Letters only. eg. A, B, C", SupportingTextState.ERROR)),
state = InputShellState.ERROR,
)
var inputValue2 by rememberSaveable { mutableStateOf("") }
SubTitle("Input Letter with legend", textColor = TextColor.OnSurfaceVariant)
InputLetter(
title = "Label",
inputText = inputValue2,
legendData = LegendData(SurfaceColor.CustomGreen, "Legend"),
onValueChanged = {
if (it != null) {
inputValue2 = it
}
},
)

var inputValue3 by rememberSaveable { mutableStateOf("") }

SubTitle("Input Letter with Supporting text", textColor = TextColor.OnSurfaceVariant)
InputLetter(
title = "Label",
inputText = inputValue3,
supportingText = listOf(SupportingTextData("Supporting text", SupportingTextState.DEFAULT)),
onValueChanged = {
if (it != null) {
inputValue3 = it
}
},
)

var inputValue4 by rememberSaveable { mutableStateOf("") }

SubTitle("Input Letter with Supporting text and legend", textColor = TextColor.OnSurfaceVariant)

InputLetter(
title = "Label",
inputText = inputValue4,
supportingText = listOf(
SupportingTextData(
"Supporting text",
SupportingTextState.DEFAULT,
),
),
legendData = LegendData(SurfaceColor.CustomGreen, "Legend"),
onValueChanged = {
if (it != null) {
inputValue4 = it
}
},
)
SubTitle("Input Letter with error and warning text and legend", textColor = TextColor.OnSurfaceVariant)
var inputValue5 by rememberSaveable { mutableStateOf("") }

InputLetter(
title = "Label",
inputText = inputValue5,
supportingText = listOf(
SupportingTextData("Supporting text", SupportingTextState.DEFAULT),
SupportingTextData("Supporting text", SupportingTextState.WARNING),
SupportingTextData("Supporting text", SupportingTextState.ERROR),

),
legendData = LegendData(SurfaceColor.CustomGreen, "Legend"),
state = InputShellState.ERROR,
imeAction = ImeAction.Done,
onValueChanged = {
if (it != null) {
inputValue5 = it
}
},
)
var inputValue6 by rememberSaveable { mutableStateOf("") }

SubTitle("Disabled Input Letter ", textColor = TextColor.OnSurfaceVariant)
InputLetter(
title = "Label",
inputText = inputValue6,
state = InputShellState.DISABLED,
onValueChanged = {
if (it != null) {
inputValue6 = it
}
},
)

var inputValue7 by rememberSaveable { mutableStateOf("A") }

SubTitle("Disabled Input Letter with content ", textColor = TextColor.OnSurfaceVariant)
InputLetter(
title = "Label",
inputText = inputValue7,
state = InputShellState.DISABLED,
onValueChanged = {
if (it != null) {
inputValue7 = it
}
},
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
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

/**
* DHIS2 Input Letter. Wraps DHIS · [InputShell].
* Component that only allows a single character,
* must be a single letter
* @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 modifier allows a modifier to be passed externally
*/
@Composable
fun InputLetter(
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,
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,
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)
}
},
)
},
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -167,4 +167,4 @@ enum class SupportingTextState(val color: Color) {
ERROR(SurfaceColor.Error),
}

data class SupportingTextData(val text: String, val state: SupportingTextState)
data class SupportingTextData(val text: String, val state: SupportingTextState = SupportingTextState.DEFAULT)
Loading

0 comments on commit 782861f

Please sign in to comment.