From bd5157d05e1fd7b2b86ebc6de90fa9dce95562b6 Mon Sep 17 00:00:00 2001 From: Siddharth Agarwal Date: Tue, 16 Jan 2024 19:18:33 +0530 Subject: [PATCH] Androapp 5820 mobile UI implement input chip component (#173) * rename `Chip` to `FilterChip` * rename `Chip` file to `FilterChip` * add `InputChip` component * fix lint error --------- Co-authored-by: Siddharth Agarwal --- .../kotlin/org/hisp/dhis/common/App.kt | 2 +- .../hisp/dhis/common/screens/ChipsScreen.kt | 56 +++++++++-- .../component/{Chip.kt => FilterChip.kt} | 4 +- .../ui/designsystem/component/InputChip.kt | 96 +++++++++++++++++++ 4 files changed, 147 insertions(+), 11 deletions(-) rename designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/{Chip.kt => FilterChip.kt} (97%) create mode 100644 designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputChip.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 ec09cce8d..bdb25d0ee 100644 --- a/common/src/commonMain/kotlin/org/hisp/dhis/common/App.kt +++ b/common/src/commonMain/kotlin/org/hisp/dhis/common/App.kt @@ -92,7 +92,7 @@ fun App() { @Composable fun Main() { - val currentScreen = remember { mutableStateOf(Components.INPUT_RADIO_BUTTON) } + val currentScreen = remember { mutableStateOf(Components.CHIPS) } var expanded by remember { mutableStateOf(false) } Column( diff --git a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/ChipsScreen.kt b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/ChipsScreen.kt index 38ed5046a..e3662aa36 100644 --- a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/ChipsScreen.kt +++ b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/ChipsScreen.kt @@ -1,22 +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.remember import androidx.compose.runtime.setValue -import org.hisp.dhis.mobile.ui.designsystem.component.Chip +import androidx.compose.ui.Modifier import org.hisp.dhis.mobile.ui.designsystem.component.ColumnComponentContainer +import org.hisp.dhis.mobile.ui.designsystem.component.FilterChip +import org.hisp.dhis.mobile.ui.designsystem.component.InputChip +import org.hisp.dhis.mobile.ui.designsystem.component.SubTitle +import org.hisp.dhis.mobile.ui.designsystem.theme.Spacing @Composable fun ChipsScreen() { - ColumnComponentContainer(title = "Filter Chips") { + ColumnComponentContainer { + SubTitle("Input Chips") var isSelected by remember { mutableStateOf(false) } - Chip(label = "Label", selected = isSelected, onSelected = { isSelected = it }) - Chip(label = "Label", selected = !isSelected, onSelected = { isSelected = !it }) - } - ColumnComponentContainer(title = "With badges") { - Chip(label = "Label", selected = true, badge = "3") - Chip(label = "Label", selected = false, badge = "3") + var isSelected1 by remember { mutableStateOf(true) } + var isSelected2 by remember { mutableStateOf(false) } + var isSelected3 by remember { mutableStateOf(true) } + InputChip(label = "Label", selected = isSelected, onSelected = { isSelected = it }) + InputChip(label = "Label", selected = !isSelected1, onSelected = { isSelected1 = !it }) + InputChip( + label = "Label", + selected = !isSelected2, + withTrailingIcon = true, + onSelected = { isSelected2 = !it }, + onIconSelected = {}, + ) + InputChip( + label = "Label", + selected = !isSelected3, + withTrailingIcon = true, + onSelected = { isSelected3 = !it }, + onIconSelected = {}, + ) + InputChip( + label = "Label", + enabled = false, + ) + Spacer(Modifier.size(Spacing.Spacing18)) + + SubTitle("Input Chips With badges") + InputChip(label = "Label", selected = false, badge = "3") + InputChip(label = "Label", selected = true, badge = "3") + Spacer(Modifier.size(Spacing.Spacing18)) + + SubTitle("Filter Chips") + var isSelected4 by remember { mutableStateOf(false) } + FilterChip(label = "Label", selected = isSelected4, onSelected = { isSelected4 = it }) + FilterChip(label = "Label", selected = !isSelected4, onSelected = { isSelected4 = !it }) + Spacer(Modifier.size(Spacing.Spacing18)) + + SubTitle("Filter Chips With badges") + FilterChip(label = "Label", selected = true, badge = "3") + FilterChip(label = "Label", selected = false, badge = "3") } } diff --git a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/Chip.kt b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/FilterChip.kt similarity index 97% rename from designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/Chip.kt rename to designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/FilterChip.kt index c7bd84a95..b994f0509 100644 --- a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/Chip.kt +++ b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/FilterChip.kt @@ -28,7 +28,7 @@ import org.hisp.dhis.mobile.ui.designsystem.theme.TextColor @OptIn(ExperimentalMaterial3Api::class) @Composable -fun Chip( +fun FilterChip( modifier: Modifier = Modifier, label: String, selected: Boolean = false, @@ -46,7 +46,7 @@ fun Chip( selectedContainerColor = SurfaceColor.Container, ), border = FilterChipDefaults.filterChipBorder( - borderColor = Outline.Medium, + borderColor = Outline.Dark, ), leadingIcon = if (selected) { { diff --git a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputChip.kt b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputChip.kt new file mode 100644 index 000000000..3d0d7e174 --- /dev/null +++ b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/InputChip.kt @@ -0,0 +1,96 @@ +package org.hisp.dhis.mobile.ui.designsystem.component + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.size +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.Close +import androidx.compose.material.ripple.LocalRippleTheme +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.FilterChipDefaults +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +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.layout.onSizeChanged +import androidx.compose.ui.unit.IntOffset +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 +import org.hisp.dhis.mobile.ui.designsystem.theme.TextColor + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun InputChip( + modifier: Modifier = Modifier, + label: String, + selected: Boolean = false, + withTrailingIcon: Boolean = false, + enabled: Boolean = true, + onSelected: ((Boolean) -> Unit)? = null, + onIconSelected: (() -> Unit)? = null, + badge: String? = null, +) { + Box(modifier = modifier) { + CompositionLocalProvider(LocalRippleTheme provides Ripple.CustomDHISRippleTheme) { + androidx.compose.material3.InputChip( + enabled = enabled, + onClick = { + onSelected?.invoke(!selected) + }, + label = { + Text( + label, + color = if (enabled) { + TextColor.OnSurfaceVariant + } else { + TextColor.OnDisabledSurface + }, + ) + }, + selected = selected, + colors = FilterChipDefaults.filterChipColors( + containerColor = SurfaceColor.SurfaceBright, + selectedContainerColor = SurfaceColor.Container, + ), + border = FilterChipDefaults.filterChipBorder( + borderColor = Outline.Dark, + disabledBorderColor = Outline.Medium, + ), + trailingIcon = if (withTrailingIcon && enabled) { + { + Icon( + imageVector = Icons.Outlined.Close, + tint = TextColor.OnSurfaceVariant, + contentDescription = "Close icon", + modifier = Modifier + .size(FilterChipDefaults.IconSize) + .clickable { + onIconSelected?.invoke() + }, + ) + } + } else { + null + }, + ) + } + badge?.let { + var offset by remember { mutableStateOf(IntOffset(0, 0)) } + Badge( + modifier = Modifier + .align(Alignment.TopEnd) + .onSizeChanged { offset = IntOffset(it.width / 3, it.height / 3) } + .offset { offset }, + text = badge, + ) + } + } +}