Refactor chips

This commit is contained in:
Sad Ellie 2023-09-26 23:29:56 +03:00
parent 533c94db6b
commit 58359a2a2d
2 changed files with 171 additions and 110 deletions

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
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 = ""
)
}

View File

@ -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() {