Skip to content

Commit

Permalink
add input yes only switch component
Browse files Browse the repository at this point in the history
  • Loading branch information
Siddharth Agarwal committed Sep 21, 2023
1 parent 48a9c6f commit 6956d13
Show file tree
Hide file tree
Showing 7 changed files with 269 additions and 3 deletions.
2 changes: 2 additions & 0 deletions common/src/commonMain/kotlin/org/hisp/dhis/common/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import org.hisp.dhis.common.screens.InputPositiveIntegerScreen
import org.hisp.dhis.common.screens.InputRadioButtonScreen
import org.hisp.dhis.common.screens.InputScreen
import org.hisp.dhis.common.screens.InputTextScreen
import org.hisp.dhis.common.screens.InputYesOnlySwitchScreen
import org.hisp.dhis.common.screens.LegendDescriptionScreen
import org.hisp.dhis.common.screens.LegendScreen
import org.hisp.dhis.common.screens.ProgressScreen
Expand Down Expand Up @@ -139,6 +140,7 @@ fun Main() {
Components.BADGES -> BadgesScreen()
Components.SWITCH -> SwitchScreen()
Components.INPUT_RADIO_BUTTON -> InputRadioButtonScreen()
Components.INPUT_YES_ONLY_SWITCH -> InputYesOnlySwitchScreen()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,5 @@ enum class Components(val label: String) {
ICON_CARDS("Icon Cards"),
INPUT_RADIO_BUTTON("Input Radio Button"),
SWITCH("Switch"),
INPUT_YES_ONLY_SWITCH("Input yes only switch"),
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
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.InputShellState
import org.hisp.dhis.mobile.ui.designsystem.component.InputYesOnlySwitch
import org.hisp.dhis.mobile.ui.designsystem.theme.Spacing

@Composable
fun InputYesOnlySwitchScreen() {
ColumnComponentContainer {
var isSelected by rememberSaveable { mutableStateOf(false) }
var isSelected1 by rememberSaveable { mutableStateOf(true) }
var isSelected2 by rememberSaveable { mutableStateOf(false) }
var isSelected3 by rememberSaveable { mutableStateOf(true) }
var isSelected4 by rememberSaveable { mutableStateOf(false) }
InputYesOnlySwitch(
title = "Label",
isChecked = isSelected,
) {
isSelected = !isSelected
}
Spacer(Modifier.size(Spacing.Spacing18))
InputYesOnlySwitch(
title = "Label",
isChecked = isSelected1,
) {
isSelected1 = !isSelected1
}
Spacer(Modifier.size(Spacing.Spacing18))
InputYesOnlySwitch(
title = "Label",
isChecked = isSelected2,
state = InputShellState.ERROR,
) {
isSelected2 = !isSelected2
}
Spacer(Modifier.size(Spacing.Spacing18))
InputYesOnlySwitch(
title = "Label",
isChecked = isSelected3,
state = InputShellState.DISABLED,
) {
isSelected3 = !isSelected3
}
Spacer(Modifier.size(Spacing.Spacing18))
InputYesOnlySwitch(
title = "Label",
isChecked = isSelected4,
state = InputShellState.DISABLED,
) {
isSelected4 = !isSelected4
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,10 @@ fun InputShell(
.padding(end = Spacing.Spacing4),
verticalArrangement = Arrangement.Center,
) {
val titleText = if (isRequiredField) "$title *" else title
InputShellLabelText(titleText, textColor = indicatorColor)
if (title.isNotEmpty()) {
val titleText = if (isRequiredField) "$title *" else title
InputShellLabelText(titleText, textColor = indicatorColor)
}
inputField?.invoke()
}
Row(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package org.hisp.dhis.mobile.ui.designsystem.component

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
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.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.platform.testTag
import org.hisp.dhis.mobile.ui.designsystem.theme.Spacing

@Composable
fun InputYesOnlySwitch(
title: String,
modifier: Modifier = Modifier,
state: InputShellState = InputShellState.UNFOCUSED,
supportingText: List<SupportingTextData>? = null,
legendData: LegendData? = null,
isRequired: Boolean = false,
isChecked: Boolean,
onClick: (Boolean) -> Unit,
) {
var indicatorColor by remember { mutableStateOf(InputShellState.UNFOCUSED.color) }
InputShell(
modifier = modifier
.onFocusChanged {
indicatorColor =
if (it.isFocused && state != InputShellState.ERROR && state != InputShellState.WARNING) InputShellState.FOCUSED.color else state.color
}
.testTag("INPUT_YES_ONLY_SWITCH"),
isRequiredField = isRequired,
title = "",
state = state,
legend = {
legendData?.let {
Legend(legendData, modifier.testTag("INPUT_YES_ONLY_SWITCH_LEGEND"))
}
},
supportingText = {
supportingText?.forEach { label ->
SupportingText(
label.text,
label.state,
modifier = modifier.testTag("INPUT_YES_ONLY_SWITCH_SUPPORTING_TEXT"),
)
}
},
inputField = {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(end = Spacing.Spacing12, bottom = Spacing.Spacing4),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween,
) {
Title(
text = title,
textColor = indicatorColor,
)
Switch(
isChecked = isChecked,
enabled = state != InputShellState.DISABLED,
) {
onClick.invoke(it)
}
}
},
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import androidx.compose.material3.SwitchDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import org.hisp.dhis.mobile.ui.designsystem.theme.Outline
import org.hisp.dhis.mobile.ui.designsystem.theme.Ripple
import org.hisp.dhis.mobile.ui.designsystem.theme.SurfaceColor
Expand All @@ -25,7 +26,7 @@ fun Switch(
) {
CompositionLocalProvider(LocalRippleTheme provides Ripple.CustomDHISRippleTheme) {
Switch(
modifier = modifier,
modifier = modifier.testTag("SWITCH"),
checked = isChecked,
onCheckedChange = { onCheckedChange.invoke(isChecked) },
enabled = enabled,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
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.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.test.assertHasClickAction
import androidx.compose.ui.test.assertIsFocused
import androidx.compose.ui.test.assertIsNotEnabled
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performClick
import org.hisp.dhis.mobile.ui.designsystem.theme.SurfaceColor
import org.junit.Rule
import org.junit.Test

class InputYesOnlySwitchTest {

@get:Rule
val rule = createComposeRule()

@Test
fun shouldDisplayInputYesOnlySwitchCorrectly() {
rule.setContent {
var selectedItem by remember {
mutableStateOf(false)
}
InputYesOnlySwitch(
title = "Label",
isChecked = selectedItem,
modifier = Modifier.testTag("INPUT_YES_ONLY_SWITCH"),
onClick = {
selectedItem = it
},
)
}
rule.onNodeWithTag("INPUT_YES_ONLY_SWITCH").assertExists()
rule.onNodeWithTag("INPUT_YES_ONLY_SWITCH_LEGEND").assertDoesNotExist()
rule.onNodeWithTag("INPUT_YES_ONLY_SWITCH_SUPPORTING_TEXT").assertDoesNotExist()
}

@Test
fun shouldAllowUserSelectionWhenEnabled() {
rule.setContent {
var selectedItem by remember {
mutableStateOf(false)
}
InputYesOnlySwitch(
title = "Label",
isChecked = selectedItem,
modifier = Modifier.testTag("INPUT_YES_ONLY_SWITCH"),
onClick = {
selectedItem = it
},
)
}
rule.onNodeWithTag("INPUT_YES_ONLY_SWITCH").assertExists()
rule.onNodeWithTag("SWITCH").performClick()
rule.onNodeWithTag("SWITCH").assertIsFocused()
}

@Test
fun shouldNotAllowUserSelectionWhenDisabled() {
rule.setContent {
var selectedItem by remember {
mutableStateOf(false)
}
InputYesOnlySwitch(
title = "Label",
isChecked = selectedItem,
state = InputShellState.DISABLED,
onClick = {
selectedItem = it
},
)
}
rule.onNodeWithTag("INPUT_YES_ONLY_SWITCH").assertExists()
rule.onNodeWithTag("SWITCH").performClick()
rule.onNodeWithTag("SWITCH").assertIsNotEnabled()
}

@Test
fun shouldShowLegendCorrectly() {
rule.setContent {
var selectedItem by remember {
mutableStateOf(false)
}
InputYesOnlySwitch(
title = "Label",
isChecked = selectedItem,
legendData = LegendData(SurfaceColor.CustomGreen, "Legend"),
onClick = {
selectedItem = it
},
)
}

rule.onNodeWithTag("INPUT_YES_ONLY_SWITCH").assertExists()
rule.onNodeWithTag("INPUT_YES_ONLY_SWITCH_LEGEND").assertExists()
rule.onNodeWithTag("INPUT_YES_ONLY_SWITCH_LEGEND").assertHasClickAction()
}

@Test
fun shouldShowSupportingTextCorrectly() {
rule.setContent {
var selectedItem by remember {
mutableStateOf(false)
}
InputYesOnlySwitch(
title = "Label",
isChecked = selectedItem,
supportingText = listOf(SupportingTextData("Supporting text", SupportingTextState.DEFAULT)),
onClick = {
selectedItem = it
},
)
}
rule.onNodeWithTag("INPUT_YES_ONLY_SWITCH").assertExists()
rule.onNodeWithTag("INPUT_YES_ONLY_SWITCH_SUPPORTING_TEXT").assertExists()
}
}

0 comments on commit 6956d13

Please sign in to comment.