Skip to content

Commit

Permalink
Merge pull request #76 from AdultOfNineteen/feature/issue-75
Browse files Browse the repository at this point in the history
[FEAT] 와인 작성 시 컬러 피커 개선
  • Loading branch information
DongChyeon authored May 17, 2024
2 parents 150cdd1 + da58dfb commit f2050e3
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import java.lang.Integer.min

@Composable
fun ColorSlider(
initialColor: Color,
onValueChange: (Color) -> Unit,
modifier: Modifier = Modifier,
thumbColor: Color = Color.White,
Expand All @@ -59,7 +60,7 @@ fun ColorSlider(
trackHeight: Dp,
thumbSize: Dp
) {
var thumbX by remember { mutableFloatStateOf(0f) }
var thumbX by remember { mutableFloatStateOf(-1f) }
var isDragging by remember { mutableStateOf(false) }

Box(
Expand Down Expand Up @@ -111,6 +112,11 @@ fun ColorSlider(
) {
val height = size.height

if (thumbX == -1f) {
// 최초 1회 initialColor에 해당하는 thumbX 계산
thumbX = calculatePositionForColor(initialColor, size.width, barColors)
}

drawCircle(
color = thumbColor,
radius = thumbSize.toPx() / 2,
Expand All @@ -123,7 +129,9 @@ fun ColorSlider(
private fun isInCircle(x: Float, y: Float, centerX: Float, centerY: Float, radius: Float): Boolean {
val dx = x - centerX
val dy = y - centerY
return (dx * dx + dy * dy) <= (radius * radius)

// 원의 반지름의 1.5배 이내에 있는지 확인 (터치 영역 개선을 위해 1.5배로 설정)
return (dx * dx + dy * dy) <= (radius * radius * 1.5f)
}

private fun calculateColorForPosition(
Expand All @@ -138,10 +146,61 @@ private fun calculateColorForPosition(
return lerp(startColor, endColor, fraction * (barColors.size - 1) - colorPosition)
}

private fun calculatePositionForColor(
color: Color,
width: Float,
barColors: List<Color>
): Float {
var minDistance = Float.MAX_VALUE
var closestFraction = -1f

for (i in 0 until barColors.size - 1) {
val startColor = barColors[i]
val endColor = barColors[i + 1]
val interpolatedColor = lerp(startColor, endColor, 0.5f) // 중간 색상을 보간하여 사용
val distance = calculateColorDistance(color, interpolatedColor)

if (distance < minDistance) {
minDistance = distance
val fraction = i.toFloat() / (barColors.size - 1)
closestFraction = adjustFraction(fraction, i, barColors)
}
}

return closestFraction * width
}

/***
* 두 색상 사이의 거리를 고려하여 보정된 fraction을 반환합니다.
*/
private fun adjustFraction(
fraction: Float,
colorIndex: Int,
barColors: List<Color>
): Float {
val previousColor = if (colorIndex > 0) barColors[colorIndex - 1] else barColors[colorIndex]
val nextColor = if (colorIndex < barColors.size - 1) barColors[colorIndex + 1] else barColors[colorIndex]

val distance = calculateColorDistance(previousColor, nextColor)
val adjustedFraction = fraction + (1f / (barColors.size - 1)) * distance
return adjustedFraction.coerceIn(0f, 1f)
}


/**
* 두 색상 사이의 유클리드 거리를 계산합니다.
*/
private fun calculateColorDistance(color1: Color, color2: Color): Float {
val deltaL = color2.red - color1.red
val deltaA = color2.green - color1.green
val deltaB = color2.blue - color1.blue
return kotlin.math.sqrt(deltaL * deltaL + deltaA * deltaA + deltaB * deltaB)
}

@Preview
@Composable
fun PreviewColorSlider() {
var barColors = listOf(
val barColors = listOf(
Color(0xFF59002B),
Color(0xFF6B3036),
Color(0xFF852223),
Expand Down Expand Up @@ -179,6 +238,7 @@ fun PreviewColorSlider() {
)

ColorSlider(
initialColor = barColors[6],
onValueChange = { currentColor = it },
barColors = barColors,
trackHeight = 10.dp,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,12 @@ fun NoteWineInfoColorAndSmellScreen(
verticalArrangement = Arrangement.Center,
) {
WineColorPicker(
initialColor = uiState.initialColor,
currentColor = uiState.wineNote.color,
barColors = uiState.barColors
) { viewModel.updateColor(it) }
) {
viewModel.updateColor(it)
}
HeightSpacer(35.dp)
WineFlavorPicker(
wineSmellKeywords = uiState.wineSmellKeywords,
Expand Down Expand Up @@ -200,7 +203,6 @@ private fun WineFlavorPicker(
}
}

@OptIn(ExperimentalLayoutApi::class)
@Composable
private fun WineSmellContainer(
wineSmellKeyword: WineSmellKeyword,
Expand Down Expand Up @@ -234,6 +236,7 @@ private fun WineSmellContainer(

@Composable
private fun WineColorPicker(
initialColor: Color,
currentColor: Color,
barColors: List<Color>,
updateCurrentColor: (Color) -> Unit,
Expand Down Expand Up @@ -286,6 +289,7 @@ private fun WineColorPicker(
)

ColorSlider(
initialColor = initialColor,
onValueChange = updateCurrentColor,
barColors = barColors,
trackHeight = 10.dp,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class NoteWriteContract {
Color(0xFFF1FBCB),
Color(0xFFD5DBB5)
),
val initialColor: Color = barColors[0],
val searchWinesCount: Long = 0,
val selectedWine: SearchWine = SearchWine.default(),
val selectedWineInfo: Wine = Wine.default(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,9 @@ class NoteWriteViewModel @Inject constructor(
) : BaseViewModel<NoteWriteContract.State, NoteWriteContract.Event, NoteWriteContract.Effect>(
initialState = NoteWriteContract.State()
) {
private val noteId: Int
private val noteId: Int = savedStateHandle.get<String>("noteId")?.toInt() ?: -1

init {
noteId = savedStateHandle.get<String>("noteId")?.toInt() ?: -1
updateState(currentState.copy(mode = if (noteId == -1) EditMode.ADD else EditMode.UPDATE))
}

Expand All @@ -65,6 +64,7 @@ class NoteWriteViewModel @Inject constructor(

updateState(
currentState.copy(
initialColor = Color(result.color.toColorInt()),
wineNote = WineNote(
wineId = -1L,
vintage = result.vintage?.toString() ?: "",
Expand Down

0 comments on commit f2050e3

Please sign in to comment.