From 58359a2a2d8ada491cb37c683e81a95df7d1a7ad Mon Sep 17 00:00:00 2001 From: Sad Ellie Date: Tue, 26 Sep 2023 23:29:56 +0300 Subject: [PATCH] Refactor chips --- .../unitto/core/ui/common/UnittoChip.kt | 144 ++++++++++++++++++ .../feature/converter/components/ChipsRow.kt | 137 ++++------------- 2 files changed, 171 insertions(+), 110 deletions(-) create mode 100644 core/ui/src/main/java/com/sadellie/unitto/core/ui/common/UnittoChip.kt diff --git a/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/UnittoChip.kt b/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/UnittoChip.kt new file mode 100644 index 00000000..2906700c --- /dev/null +++ b/core/ui/src/main/java/com/sadellie/unitto/core/ui/common/UnittoChip.kt @@ -0,0 +1,144 @@ +/* + * Unitto is a unit converter for Android + * Copyright (c) 2023 Elshan Agaev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sadellie.unitto.core.ui.common + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Check +import androidx.compose.material.icons.filled.Settings +import androidx.compose.material3.AssistChipDefaults +import androidx.compose.material3.FilterChipDefaults +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +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.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp + +@Composable +fun FilterChip( + modifier: Modifier = Modifier, + selected: Boolean, + onClick: () -> Unit, + label: String, + imageVector: ImageVector, + contentDescription: String, +) { + Row( + modifier = modifier + .background( + color = if (selected) MaterialTheme.colorScheme.primaryContainer else MaterialTheme.colorScheme.surface, + shape = FilterChipDefaults.shape + ) + .border( + width = 1.dp, + color = if (selected) Color.Transparent else MaterialTheme.colorScheme.outline, + shape = FilterChipDefaults.shape + ) + .height(FilterChipDefaults.Height) + .clickable { onClick() } + .padding(start = 8.dp, end = 16.dp), + verticalAlignment = Alignment.CenterVertically + ) { + AnimatedVisibility(visible = selected) { + Icon( + modifier = Modifier.height(FilterChipDefaults.IconSize), + imageVector = imageVector, + contentDescription = contentDescription, + tint = MaterialTheme.colorScheme.onPrimaryContainer + ) + } + Text( + modifier = Modifier.padding(start = 8.dp), + text = label, + style = MaterialTheme.typography.labelLarge, + color = if (selected) MaterialTheme.colorScheme.onPrimaryContainer else MaterialTheme.colorScheme.onSurfaceVariant + ) + } +} + +@Composable +fun AssistChip( + modifier: Modifier = Modifier, + onClick: () -> Unit, + imageVector: ImageVector, + contentDescription: String, +) { + Row( + modifier = modifier + .background( + color = MaterialTheme.colorScheme.surface, + shape = AssistChipDefaults.shape + ) + .border( + width = 1.dp, + color = MaterialTheme.colorScheme.outline, + shape = AssistChipDefaults.shape + ) + .height(32.dp) + .clickable { onClick() } + .padding(horizontal = 8.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + modifier = Modifier.height(AssistChipDefaults.IconSize), + imageVector = imageVector, + contentDescription = contentDescription, + tint = MaterialTheme.colorScheme.onPrimaryContainer + ) + } +} + +@Preview +@Composable +fun PreviewAssistChip() { + AssistChip( + onClick = {}, + imageVector = Icons.Default.Settings, + contentDescription = "" + ) +} + +@Preview +@Composable +fun PreviewFilterChip() { + var isSelected by remember { mutableStateOf(true) } + + FilterChip( + selected = isSelected, + onClick = { isSelected = !isSelected }, + label = "Label", + imageVector = Icons.Default.Check, + contentDescription = "" + ) +} diff --git a/feature/converter/src/main/java/com/sadellie/unitto/feature/converter/components/ChipsRow.kt b/feature/converter/src/main/java/com/sadellie/unitto/feature/converter/components/ChipsRow.kt index 2057cdd5..0ab23c81 100644 --- a/feature/converter/src/main/java/com/sadellie/unitto/feature/converter/components/ChipsRow.kt +++ b/feature/converter/src/main/java/com/sadellie/unitto/feature/converter/components/ChipsRow.kt @@ -18,23 +18,17 @@ package com.sadellie.unitto.feature.converter.components -import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.animateDp import androidx.compose.animation.core.animateFloat import androidx.compose.animation.core.tween import androidx.compose.animation.core.updateTransition -import androidx.compose.foundation.background -import androidx.compose.foundation.border -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size @@ -43,7 +37,6 @@ import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Check @@ -51,23 +44,20 @@ import androidx.compose.material.icons.filled.ExpandMore import androidx.compose.material.icons.filled.Settings import androidx.compose.material3.Icon import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text 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.draw.clip import androidx.compose.ui.draw.clipToBounds import androidx.compose.ui.draw.rotate -import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.sadellie.unitto.core.base.R +import com.sadellie.unitto.core.ui.common.AssistChip +import com.sadellie.unitto.core.ui.common.FilterChip import com.sadellie.unitto.data.model.ALL_UNIT_GROUPS import com.sadellie.unitto.data.model.UnitGroup @@ -97,26 +87,14 @@ internal fun ChipsRow( horizontalArrangement = Arrangement.spacedBy(8.dp) ) { items(items, key = { it.name }) { item -> - val isSelected: Boolean = item == chosenUnitGroup - UnittoFilterChip( - isSelected = isSelected, - selectAction = { selectAction(if (item == chosenUnitGroup) null else item) } - ) { - AnimatedVisibility(visible = isSelected) { - Icon( - modifier = Modifier.height(18.dp), - imageVector = Icons.Default.Check, - contentDescription = stringResource(R.string.checked_filter_description), - tint = MaterialTheme.colorScheme.onPrimaryContainer - ) - } - Text( - modifier = Modifier.padding(start = 8.dp), - text = stringResource(item.res), - style = MaterialTheme.typography.labelLarge, - color = if (isSelected) MaterialTheme.colorScheme.onPrimaryContainer else MaterialTheme.colorScheme.onSurfaceVariant - ) - } + val selected: Boolean = item == chosenUnitGroup + FilterChip( + selected = selected, + onClick = { selectAction(if (selected) null else item) }, + label = stringResource(item.res), + imageVector = Icons.Default.Check, + contentDescription = stringResource(R.string.checked_filter_description) + ) } /** @@ -125,17 +103,11 @@ internal fun ChipsRow( * scrolling right (to the last one). */ item("settings") { - UnittoFilterChip( - isSelected = false, - selectAction = navigateToSettingsAction, - paddingValues = PaddingValues(horizontal = 8.dp) - ) { - Icon( - modifier = Modifier.height(18.dp), - imageVector = Icons.Default.Settings, - contentDescription = stringResource(R.string.open_settings_description) - ) - } + AssistChip( + onClick = navigateToSettingsAction, + imageVector = Icons.Default.Settings, + contentDescription = stringResource(R.string.open_settings_description) + ) } } } @@ -175,38 +147,20 @@ fun ChipsFlexRow( verticalArrangement = Arrangement.spacedBy(8.dp) ) { items.forEach { item -> - val isSelected: Boolean = item == chosenUnitGroup - UnittoFilterChip( - isSelected = isSelected, - selectAction = { selectAction(if (item == chosenUnitGroup) null else item) } - ) { - AnimatedVisibility(visible = isSelected) { - Icon( - modifier = Modifier.height(18.dp), - imageVector = Icons.Default.Check, - contentDescription = stringResource(R.string.checked_filter_description), - tint = MaterialTheme.colorScheme.onPrimaryContainer - ) - } - Text( - modifier = Modifier.padding(start = 8.dp), - text = stringResource(item.res), - style = MaterialTheme.typography.labelLarge, - color = if (isSelected) MaterialTheme.colorScheme.onPrimaryContainer else MaterialTheme.colorScheme.onSurfaceVariant - ) - } - } - UnittoFilterChip( - isSelected = false, - selectAction = navigateToSettingsAction, - paddingValues = PaddingValues(horizontal = 8.dp) - ) { - Icon( - modifier = Modifier.height(18.dp), - imageVector = Icons.Default.Settings, - contentDescription = stringResource(R.string.open_settings_description) + val selected: Boolean = item == chosenUnitGroup + FilterChip( + selected = selected, + onClick = { selectAction(if (selected) null else item) }, + label = stringResource(item.res), + imageVector = Icons.Default.Check, + contentDescription = stringResource(R.string.checked_filter_description) ) } + AssistChip( + onClick = navigateToSettingsAction, + imageVector = Icons.Default.Settings, + contentDescription = stringResource(R.string.open_settings_description) + ) } IconButton( @@ -224,43 +178,6 @@ fun ChipsFlexRow( } } -/** - * Basic chip implementation - * - * @param isSelected Chip state. - * @param selectAction Action to perform when clicking chip. - * @param paddingValues Padding values applied to Row. - * @param content Content of the list. Icon and/or label. - */ -@Composable -private fun UnittoFilterChip( - isSelected: Boolean, - selectAction: () -> Unit, - paddingValues: PaddingValues = PaddingValues(start = 8.dp, end = 16.dp), - content: @Composable RowScope.() -> Unit -) { - val chipShape = RoundedCornerShape(8.dp) - Row( - modifier = Modifier - .height(32.dp) - .clip(chipShape) - .background( - if (isSelected) MaterialTheme.colorScheme.primaryContainer else Color.Transparent - ) - // Remove border when selected - .border( - 1.dp, - if (isSelected) Color.Transparent else MaterialTheme.colorScheme.outline, - chipShape - ) - .clickable { selectAction() } - .padding(paddingValues), - verticalAlignment = Alignment.CenterVertically - ) { - content() - } -} - @Preview @Composable fun PreviewUnittoChips() {