From 6778c14c41e9d20f9158c254c595e5d501a8a7ba Mon Sep 17 00:00:00 2001 From: jinukeu Date: Sun, 3 Dec 2023 20:39:49 +0900 Subject: [PATCH 1/3] feat: SuwikiDropDown.kt --- .../component/dropdown/SuwikiDropDown.kt | 137 ++++++++++++++++++ .../res/drawable/ic_dropdown_arrow_down.xml | 11 ++ 2 files changed, 148 insertions(+) create mode 100644 core/designsystem/src/main/java/com/suwiki/core/designsystem/component/dropdown/SuwikiDropDown.kt create mode 100644 core/designsystem/src/main/res/drawable/ic_dropdown_arrow_down.xml diff --git a/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/dropdown/SuwikiDropDown.kt b/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/dropdown/SuwikiDropDown.kt new file mode 100644 index 000000000..f09843996 --- /dev/null +++ b/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/dropdown/SuwikiDropDown.kt @@ -0,0 +1,137 @@ +package com.suwiki.core.designsystem.component.dropdown + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuItem +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.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.DpOffset +import androidx.compose.ui.unit.dp +import com.suwiki.core.designsystem.R + +@Composable +fun SuwikiDropDownMenu( + label: String = "", + onClickLabel: () -> Unit = {}, + onDismissRequest: () -> Unit = {}, + expanded: Boolean = false, + content: @Composable ColumnScope.() -> Unit, +) { + Column( + horizontalAlignment = Alignment.Start, + ) { + Row( + modifier = Modifier + .clip(RoundedCornerShape(10.dp)) + .clickable(onClick = onClickLabel) + .background(Color.LightGray) + .padding( + horizontal = 9.dp, + vertical = 6.dp, + ), + verticalAlignment = Alignment.CenterVertically, + ) { + Text( + text = label, + ) + Image( + painter = painterResource(id = R.drawable.ic_dropdown_arrow_down), + contentDescription = "", + ) + } + + MaterialTheme( + shapes = MaterialTheme.shapes.copy(extraSmall = RoundedCornerShape(10.dp)), + ) { + DropdownMenu( + modifier = Modifier + .width(106.dp) + .background(Color.White) + .padding(vertical = 8.dp) + .clip(RoundedCornerShape(20.dp)), + offset = DpOffset(x = 0.dp, y = 6.dp), + expanded = expanded, + onDismissRequest = onDismissRequest, + content = content, + ) + } + } +} + +@Preview(showSystemUi = true) +@Composable +fun SuwikiDropDownMenuPreview() { + var isSemesterDropDownExpanded by remember { + mutableStateOf(false) + } + + var isExamDropdownExpanded by remember { + mutableStateOf(false) + } + + Column { + SuwikiDropDownMenu( + label = "수강학기 선택", + expanded = isSemesterDropDownExpanded, + onClickLabel = { isSemesterDropDownExpanded = true }, + onDismissRequest = { isSemesterDropDownExpanded = false }, + ) { + repeat(4) { + SuwikiDropdownMenuItem( + text = "menu", + ) + } + } + + SuwikiDropDownMenu( + label = "시험유형 선택", + expanded = isExamDropdownExpanded, + onClickLabel = { isExamDropdownExpanded = true }, + onDismissRequest = { isExamDropdownExpanded = false }, + ) { + repeat(4) { + SuwikiDropdownMenuItem( + text = "menu", + ) + } + } + } +} + +@Composable +fun SuwikiDropdownMenuItem( + onClick: () -> Unit = {}, + text: String = "", +) { + DropdownMenuItem( + modifier = Modifier.fillMaxWidth(), + onClick = onClick, + text = { + Text( + text = text, + textAlign = TextAlign.Start, + ) + }, + ) +} diff --git a/core/designsystem/src/main/res/drawable/ic_dropdown_arrow_down.xml b/core/designsystem/src/main/res/drawable/ic_dropdown_arrow_down.xml new file mode 100644 index 000000000..00891344a --- /dev/null +++ b/core/designsystem/src/main/res/drawable/ic_dropdown_arrow_down.xml @@ -0,0 +1,11 @@ + + + From 295dbcd03c3516075918d213fc4ecec8b321adf2 Mon Sep 17 00:00:00 2001 From: jinukeu Date: Mon, 4 Dec 2023 12:14:26 +0900 Subject: [PATCH 2/3] feat: SuwikiSlider --- .../core/designsystem/component/Sample.kt | 1 - .../component/slider/SuwikiSlider.kt | 94 +++++++++++++++++++ .../component/slider/SuwikiSliderThumb.kt | 35 +++++++ .../slider/SuwikiSliderThumbWithLabel.kt | 50 ++++++++++ .../component/slider/SuwikiSliderTrack.kt | 61 ++++++++++++ .../res/drawable/ic_slider_thumb_hovered.xml | 18 ++++ 6 files changed, 258 insertions(+), 1 deletion(-) delete mode 100644 core/designsystem/src/main/java/com/suwiki/core/designsystem/component/Sample.kt create mode 100644 core/designsystem/src/main/java/com/suwiki/core/designsystem/component/slider/SuwikiSlider.kt create mode 100644 core/designsystem/src/main/java/com/suwiki/core/designsystem/component/slider/SuwikiSliderThumb.kt create mode 100644 core/designsystem/src/main/java/com/suwiki/core/designsystem/component/slider/SuwikiSliderThumbWithLabel.kt create mode 100644 core/designsystem/src/main/java/com/suwiki/core/designsystem/component/slider/SuwikiSliderTrack.kt create mode 100644 core/designsystem/src/main/res/drawable/ic_slider_thumb_hovered.xml diff --git a/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/Sample.kt b/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/Sample.kt deleted file mode 100644 index 412a23fea..000000000 --- a/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/Sample.kt +++ /dev/null @@ -1 +0,0 @@ -package com.suwiki.core.designsystem.component diff --git a/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/slider/SuwikiSlider.kt b/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/slider/SuwikiSlider.kt new file mode 100644 index 000000000..1247a04cf --- /dev/null +++ b/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/slider/SuwikiSlider.kt @@ -0,0 +1,94 @@ +package com.suwiki.core.designsystem.component.slider + +import androidx.annotation.IntRange +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Slider +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableFloatStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import kotlin.math.round + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun SuwikiSlider( + value: Float = 2.5f, + onValueChange: (Float) -> Unit = { _ -> }, + @IntRange(from = 0) + steps: Int = 9, + valueRange: ClosedFloatingPointRange = 0f..5f, + interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, +) { + var isHovering by rememberSaveable { + mutableStateOf(false) + } + + val label = (round(value * 100) / 100).toString() + + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + ) { + Slider( + modifier = Modifier.weight(1f).height(SUWIKI_THUMB_WIDTH_LABEL_HEIGHT.dp), + value = value, + onValueChange = { + isHovering = true + onValueChange(it) + }, + onValueChangeFinished = { isHovering = false }, + valueRange = valueRange, + steps = steps, + interactionSource = interactionSource, + thumb = { + if (isHovering) { + SuwikiSliderThumbWithLabel( + label = label, + ) + } else { + SuwikiSliderThumb() + } + }, + track = { + SuwikiSliderTrack( + value = value, + valueRange = valueRange, + height = 6.dp, + shape = RoundedCornerShape(4.dp), + ) + }, + ) + + Text(text = label) + } +} + +@Preview(showBackground = true, backgroundColor = 0xFFFFFF) +@Composable +fun SuwikiSliderPreview() { + var sliderPosition by rememberSaveable { + mutableFloatStateOf(2.5f) + } + + Box(modifier = Modifier.padding(vertical = 40.dp)) { + SuwikiSlider( + value = sliderPosition, + onValueChange = { sliderPosition = if (it < 0.5) 0.5F else it }, + ) + } +} diff --git a/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/slider/SuwikiSliderThumb.kt b/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/slider/SuwikiSliderThumb.kt new file mode 100644 index 000000000..7e73dac75 --- /dev/null +++ b/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/slider/SuwikiSliderThumb.kt @@ -0,0 +1,35 @@ +package com.suwiki.core.designsystem.component.slider + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp + +@Composable +fun SuwikiSliderThumb() { + Box( + modifier = Modifier.size(28.dp), + contentAlignment = Alignment.Center, + ) { + Spacer( + modifier = Modifier + .size(16.dp) + .clip(CircleShape) + .background(Color.Blue), + ) + } +} + +@Preview +@Composable +fun SuwikiSliderThumbPreview() { + SuwikiSliderThumb() +} diff --git a/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/slider/SuwikiSliderThumbWithLabel.kt b/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/slider/SuwikiSliderThumbWithLabel.kt new file mode 100644 index 000000000..3249f06f3 --- /dev/null +++ b/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/slider/SuwikiSliderThumbWithLabel.kt @@ -0,0 +1,50 @@ +package com.suwiki.core.designsystem.component.slider + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.size +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.suwiki.core.designsystem.R + +const val SUWIKI_THUMB_WIDTH_LABEL_HEIGHT = 88 + +@Composable +fun SuwikiSliderThumbWithLabel( + modifier: Modifier = Modifier, + label: String, +) { + Box( + modifier = modifier.height(SUWIKI_THUMB_WIDTH_LABEL_HEIGHT.dp), + ) { + Image( + painter = painterResource(id = R.drawable.ic_slider_thumb_hovered), + contentDescription = "", + ) + + Box( + modifier = Modifier.size(28.dp), + contentAlignment = Alignment.Center, + ) { + Text( + text = label, + textAlign = TextAlign.Center, + color = Color.White, + ) + } + } +} + +@Preview +@Composable +fun SuwikiSliderThumbWithLabelPreview() { + SuwikiSliderThumbWithLabel(label = "5.0") +} diff --git a/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/slider/SuwikiSliderTrack.kt b/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/slider/SuwikiSliderTrack.kt new file mode 100644 index 000000000..275e437d3 --- /dev/null +++ b/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/slider/SuwikiSliderTrack.kt @@ -0,0 +1,61 @@ +package com.suwiki.core.designsystem.component.slider + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp + +@Composable +@ExperimentalMaterial3Api +fun SuwikiSliderTrack( + modifier: Modifier = Modifier, + value: Float, + valueRange: ClosedFloatingPointRange, + height: Dp = 6.dp, + shape: Shape = RoundedCornerShape(4.dp) +) { + Box( + modifier = modifier + .track(height = height, shape = shape) + .background(Color.LightGray), + ) { + Box( + modifier = modifier + .progress( + value = value, + valueRange = valueRange, + height = height, + shape = shape, + ) + .background(Color.Blue), + ) + } +} + +private fun Modifier.track( + height: Dp = 6.dp, + shape: Shape = CircleShape +) = fillMaxWidth() + .heightIn(min = height) + .clip(shape) + +private fun Modifier.progress( + value: Float, + valueRange: ClosedFloatingPointRange, + height: Dp = 6.dp, + shape: Shape = CircleShape +) = + fillMaxWidth(fraction = value / valueRange.endInclusive - valueRange.start) + .heightIn(min = height) + .clip(shape) diff --git a/core/designsystem/src/main/res/drawable/ic_slider_thumb_hovered.xml b/core/designsystem/src/main/res/drawable/ic_slider_thumb_hovered.xml new file mode 100644 index 000000000..4a81fe6e9 --- /dev/null +++ b/core/designsystem/src/main/res/drawable/ic_slider_thumb_hovered.xml @@ -0,0 +1,18 @@ + + + + + From 787373056affb3c0607f8a42868a3929a21654c4 Mon Sep 17 00:00:00 2001 From: jinukeu Date: Mon, 4 Dec 2023 14:33:46 +0900 Subject: [PATCH 3/3] chore: ktlintFormat --- .../core/designsystem/component/slider/SuwikiSliderTrack.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/slider/SuwikiSliderTrack.kt b/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/slider/SuwikiSliderTrack.kt index 275e437d3..7ec2bd21b 100644 --- a/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/slider/SuwikiSliderTrack.kt +++ b/core/designsystem/src/main/java/com/suwiki/core/designsystem/component/slider/SuwikiSliderTrack.kt @@ -23,7 +23,7 @@ fun SuwikiSliderTrack( value: Float, valueRange: ClosedFloatingPointRange, height: Dp = 6.dp, - shape: Shape = RoundedCornerShape(4.dp) + shape: Shape = RoundedCornerShape(4.dp), ) { Box( modifier = modifier @@ -45,7 +45,7 @@ fun SuwikiSliderTrack( private fun Modifier.track( height: Dp = 6.dp, - shape: Shape = CircleShape + shape: Shape = CircleShape, ) = fillMaxWidth() .heightIn(min = height) .clip(shape) @@ -54,7 +54,7 @@ private fun Modifier.progress( value: Float, valueRange: ClosedFloatingPointRange, height: Dp = 6.dp, - shape: Shape = CircleShape + shape: Shape = CircleShape, ) = fillMaxWidth(fraction = value / valueRange.endInclusive - valueRange.start) .heightIn(min = height)