diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml index 8bc271fe..572ee4fe 100644 --- a/.idea/deploymentTargetSelector.xml +++ b/.idea/deploymentTargetSelector.xml @@ -5,6 +5,9 @@ + + \ No newline at end of file diff --git a/app/src/main/java/com/texthip/thip/ui/common/buttons/ActionBookButton.kt b/app/src/main/java/com/texthip/thip/ui/common/buttons/ActionBookButton.kt new file mode 100644 index 00000000..fd5ebe2f --- /dev/null +++ b/app/src/main/java/com/texthip/thip/ui/common/buttons/ActionBookButton.kt @@ -0,0 +1,83 @@ +package com.texthip.thip.ui.common.buttons + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.texthip.thip.R +import com.texthip.thip.ui.theme.ThipTheme.colors +import com.texthip.thip.ui.theme.ThipTheme.typography + +@Composable +fun ActionBookButton( + bookTitle: String = stringResource(R.string.book_title), + bookAuthor: String = stringResource(R.string.book_author), + onClick: () -> Unit = {} +) { + Box( + modifier = Modifier + .background(color = colors.DarkGrey, shape = RoundedCornerShape(12.dp)) + .clickable { + onClick() + } + .padding(top = 16.dp, bottom = 16.dp, start = 12.dp, end = 4.dp) + + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + ) { + Text( + text = bookTitle, + style = typography.smalltitle_sb600_s16_h24, + color = colors.White, + modifier = Modifier.weight(1f), + overflow = TextOverflow.Ellipsis, + maxLines = 1 + ) + + Text( + text = bookAuthor + stringResource(R.string.author), + style = typography.info_r400_s12_h24, + color = colors.Grey, + modifier = Modifier.width(100.dp), + textAlign = TextAlign.Right, + overflow = TextOverflow.Ellipsis, + maxLines = 1 + ) + + Icon( + painter = painterResource(R.drawable.ic_chevron), + contentDescription = null, + tint = colors.Grey, + ) + } + } +} + +@Preview +@Composable +private fun ActionBookButtonPreview() { + Column( + modifier = Modifier + .fillMaxSize() + .padding(30.dp) + ) { + ActionBookButton() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/texthip/thip/ui/common/buttons/ActionFillButton.kt b/app/src/main/java/com/texthip/thip/ui/common/buttons/ActionFillButton.kt new file mode 100644 index 00000000..925a58c0 --- /dev/null +++ b/app/src/main/java/com/texthip/thip/ui/common/buttons/ActionFillButton.kt @@ -0,0 +1,82 @@ +package com.texthip.thip.ui.common.buttons + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Icon +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.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.texthip.thip.R +import com.texthip.thip.ui.theme.ThipTheme.colors +import com.texthip.thip.ui.theme.ThipTheme.typography + +@Composable +fun ActionFillButton( + text: String, + backgroundColor: Color, + onClick: () -> Unit, +) { + Row( + modifier = Modifier + .fillMaxWidth() + .height(50.dp) + .background(backgroundColor) + .clickable(onClick = onClick), + horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.CenterHorizontally), + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + painter = painterResource(R.drawable.ic_write), + contentDescription = null, + tint = colors.White, + ) + + Text( + text = text, + color = colors.White, + style = typography.smalltitle_sb600_s18_h24, + ) + + Icon( + painter = painterResource(R.drawable.ic_send), + contentDescription = null, + tint = colors.White, + ) + } +} + +@Preview +@Composable +private fun ActionFillButtonPreview() { + Column( + modifier = Modifier + .fillMaxSize() + .padding(30.dp), + verticalArrangement = Arrangement.spacedBy(30.dp, Alignment.CenterVertically), + ) { + ActionFillButton( + text = stringResource(R.string.post), + backgroundColor = colors.Purple, + onClick = {} + ) + + ActionFillButton( + text = stringResource(R.string.post), + backgroundColor = colors.Grey02, + onClick = {} + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/texthip/thip/ui/common/buttons/ActionMediumButton.kt b/app/src/main/java/com/texthip/thip/ui/common/buttons/ActionMediumButton.kt new file mode 100644 index 00000000..33a0f0ec --- /dev/null +++ b/app/src/main/java/com/texthip/thip/ui/common/buttons/ActionMediumButton.kt @@ -0,0 +1,139 @@ +package com.texthip.thip.ui.common.buttons + +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.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Icon +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.graphics.painter.Painter +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.texthip.thip.R +import com.texthip.thip.ui.theme.ThipTheme.colors +import com.texthip.thip.ui.theme.ThipTheme.typography + +@Composable +fun ActionMediumButton( + text: String, + icon: Painter? = null, + contentColor: Color, + backgroundColor: Color, + hasRightIcon: Boolean = false, + modifier: Modifier = Modifier, + onClick: () -> Unit = {}, +) { + val hasLeftIcon = icon != null + + Row( + modifier = modifier + .fillMaxWidth() + .height(44.dp) + .background(color = backgroundColor, shape = RoundedCornerShape(12.dp)) + .clickable { + onClick() + }, + horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.CenterHorizontally), + verticalAlignment = Alignment.CenterVertically, + ) { + if (hasLeftIcon) { + Icon( + painter = icon, + contentDescription = null, + tint = contentColor, + ) + } + + Text( + text = text, + color = contentColor, + style = typography.smalltitle_sb600_s16_h24, + ) + + if (hasRightIcon) { + Icon( + painter = painterResource(R.drawable.ic_chevron), + contentDescription = null, + tint = contentColor, + ) + } + } +} + +@Preview +@Composable +private fun ActionMediumButtonPreview() { + Column( + modifier = Modifier + .fillMaxSize() + .padding(30.dp), + verticalArrangement = Arrangement.spacedBy(16.dp, Alignment.CenterVertically), + ) { + ActionMediumButton( + text = stringResource(R.string.add_to_my_feed), + icon = painterResource(R.drawable.ic_search), + contentColor = colors.White, + backgroundColor = colors.Grey02, + hasRightIcon = true, + modifier = Modifier.width(180.dp), + onClick = {}, + ) + + ActionMediumButton( + text = stringResource(R.string.add_to_my_feed), + icon = painterResource(R.drawable.ic_plus), + contentColor = colors.White, + backgroundColor = colors.Purple, + hasRightIcon = true, + modifier = Modifier.width(180.dp), + onClick = {}, + ) + + ActionMediumButton( + text = stringResource(R.string.add_to_my_feed), + icon = painterResource(R.drawable.ic_search), + contentColor = colors.Grey, + backgroundColor = Color.Transparent, + hasRightIcon = true, + modifier = Modifier + .width(180.dp) + .border(width = 1.dp, color = colors.Grey02, shape = RoundedCornerShape(12.dp)), + onClick = {}, + ) + + Row( + horizontalArrangement = Arrangement.spacedBy(20.dp, Alignment.CenterHorizontally), + ) { + + ActionMediumButton( + text = stringResource(R.string.yes), + contentColor = colors.White, + backgroundColor = colors.Purple, + modifier = Modifier.weight(1f), + onClick = {}, + ) + + ActionMediumButton( + text = stringResource(R.string.no), + contentColor = colors.White, + backgroundColor = colors.Grey02, + modifier = Modifier.weight(1f), + onClick = {}, + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/texthip/thip/ui/common/buttons/CheckboxButton.kt b/app/src/main/java/com/texthip/thip/ui/common/buttons/CheckboxButton.kt new file mode 100644 index 00000000..69386852 --- /dev/null +++ b/app/src/main/java/com/texthip/thip/ui/common/buttons/CheckboxButton.kt @@ -0,0 +1,49 @@ +package com.texthip.thip.ui.common.buttons + +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Checkbox +import androidx.compose.material3.CheckboxDefaults +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.texthip.thip.ui.theme.ThipTheme.colors + +@Composable +fun CheckboxButton( + isChecked: Boolean, + onCheckedChange: (Boolean) -> Unit, +) { + Checkbox( + checked = isChecked, + onCheckedChange = onCheckedChange, + modifier = + Modifier + .border(1.dp, colors.Grey01, RoundedCornerShape(8.dp)) + .size(30.dp), + colors = + CheckboxDefaults.colors( + checkmarkColor = colors.NeonGreen, + checkedColor = Color.Transparent, + uncheckedColor = Color.Transparent, + ), + ) +} + +@Preview +@Composable +private fun CheckboxButtonPreview() { + var isChecked by rememberSaveable { mutableStateOf(false) } + + CheckboxButton( + isChecked = isChecked, + onCheckedChange = { isChecked = it } + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/texthip/thip/ui/common/buttons/ExpandableFloatingButton.kt b/app/src/main/java/com/texthip/thip/ui/common/buttons/ExpandableFloatingButton.kt new file mode 100644 index 00000000..763d2010 --- /dev/null +++ b/app/src/main/java/com/texthip/thip/ui/common/buttons/ExpandableFloatingButton.kt @@ -0,0 +1,161 @@ +package com.texthip.thip.ui.common.buttons + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +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.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.FloatingActionButton +import androidx.compose.material3.Icon +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.painter.Painter +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.texthip.thip.R +import com.texthip.thip.ui.theme.ThipTheme.colors +import com.texthip.thip.ui.theme.ThipTheme.typography + +data class FabMenuItem( + val icon: Painter, + val text: String, + val onClick: () -> Unit +) + +@Composable +fun ExpandableFloatingButton( + menuItems: List +) { + var expanded by remember { mutableStateOf(false) } + + Box( + modifier = Modifier + .fillMaxSize() + .padding(16.dp), // TODO: 화면에서 버튼 위치 조정 + contentAlignment = Alignment.BottomEnd + ) { + Column( + horizontalAlignment = Alignment.End + ) { + // 펼쳐진 메뉴 + AnimatedVisibility( + visible = expanded, + enter = fadeIn(), + exit = fadeOut(), + ) { + Column( + modifier = Modifier + .padding(bottom = 80.dp, end = 16.dp) // TODO: 화면에서 버튼 위치 조정 + .width(184.dp) + .background( + color = colors.Black, + shape = RoundedCornerShape(16.dp) + ) + .border( + width = 1.dp, + color = colors.NeonGreen, + shape = RoundedCornerShape(16.dp) + ) + .padding(vertical = 24.dp, horizontal = 12.dp), + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + menuItems.forEachIndexed { index, item -> +// if (index > 0) Spacer(modifier = Modifier.height(16.dp)) + MenuItem( + icon = item.icon, + text = item.text, + onClick = { + expanded = false + item.onClick() + } + ) + } + } + } + } + + // 플로팅 버튼 + FloatingActionButton( + onClick = { expanded = !expanded }, + containerColor = if (expanded) colors.Purple else colors.DarkGrey, + contentColor = colors.NeonGreen, + shape = CircleShape, + modifier = Modifier + .padding(16.dp) + .size(56.dp) + .border(width = 2.dp, color = colors.NeonGreen50, shape = CircleShape) + ) { + Icon( + painter = if (expanded) painterResource(R.drawable.ic_x) else painterResource(R.drawable.ic_plus), + modifier = Modifier.size(24.dp), + tint = colors.NeonGreen, + contentDescription = null + ) + } + } +} + +@Composable +fun MenuItem( + icon: Painter, + text: String, + onClick: () -> Unit +) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .clickable { onClick() } + ) { + Icon( + painter = icon, + contentDescription = null, + tint = colors.White, + modifier = Modifier.size(24.dp) + ) + Spacer(modifier = Modifier.width(8.dp)) + Text( + text = text, + color = colors.White, + style = typography.menu_m500_s16_h24 + ) + } +} + +@Preview +@Composable +private fun ExpandableFabPreview() { + ExpandableFloatingButton( + menuItems = listOf( + FabMenuItem( + icon = painterResource(R.drawable.ic_write), + text = stringResource(R.string.write_record), + onClick = { } + ), + FabMenuItem( + icon = painterResource(R.drawable.ic_vote), + text = stringResource(R.string.create_vote), + onClick = { } + ) + ) + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/texthip/thip/ui/common/buttons/FilterButton.kt b/app/src/main/java/com/texthip/thip/ui/common/buttons/FilterButton.kt new file mode 100644 index 00000000..af36e038 --- /dev/null +++ b/app/src/main/java/com/texthip/thip/ui/common/buttons/FilterButton.kt @@ -0,0 +1,130 @@ +package com.texthip.thip.ui.common.buttons + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Icon +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.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.texthip.thip.R +import com.texthip.thip.ui.theme.ThipTheme.colors +import com.texthip.thip.ui.theme.ThipTheme.typography + +@Composable +fun FilterButton( + modifier: Modifier = Modifier, + selectedOption: String, + options: List, + onOptionSelected: (String) -> Unit +) { + var expanded by remember { mutableStateOf(false) } + + Column(modifier = modifier) { + Row( + modifier = Modifier + .fillMaxWidth() + .clickable( + interactionSource = remember { MutableInteractionSource() }, + indication = null // 클릭 효과 제거 + ) { expanded = !expanded }, + horizontalArrangement = Arrangement.End, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = selectedOption, + color = colors.Grey01, + style = typography.menu_m500_s14_h24 + ) + Icon( + painter = painterResource( + id = if (expanded) R.drawable.ic_upmore else R.drawable.ic_downmore + ), + contentDescription = "Dropdown", + tint = colors.Grey02, + modifier = Modifier.size(24.dp) + ) + + } + + // 드롭다운 애니메이션 박스 + AnimatedVisibility( + visible = expanded, + enter = fadeIn(), + exit = fadeOut() + ) { + Box( + modifier = Modifier.fillMaxWidth(), + contentAlignment = Alignment.TopEnd + ) { + Column( + modifier = Modifier + .padding(top = 8.dp) + .width(144.dp) + .border( + width = 1.dp, + color = colors.Grey01, + shape = RoundedCornerShape(16.dp) + ) + .background(color = colors.Black, shape = RoundedCornerShape(16.dp)) + .padding(vertical = 20.dp, horizontal = 12.dp), + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + options.forEach { option -> + val isSelected = option == selectedOption + Text( + text = option, + color = if (isSelected) colors.White else colors.Grey02, + style = typography.feedcopy_r400_s14_h20, + modifier = Modifier + .fillMaxWidth() + .clickable { + onOptionSelected(option) + expanded = false + } + ) + } + } + } + } + } +} + +@Preview +@Composable +private fun FilterButtonPreview() { + var selected by remember { mutableStateOf("인기순") } + val options = listOf("인기순", "정확도순") + + Column( + modifier = Modifier.fillMaxSize() + ) { + FilterButton( + selectedOption = selected, + options = options, + onOptionSelected = { selected = it } + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/texthip/thip/ui/common/buttons/FloatingButton.kt b/app/src/main/java/com/texthip/thip/ui/common/buttons/FloatingButton.kt new file mode 100644 index 00000000..976ae34d --- /dev/null +++ b/app/src/main/java/com/texthip/thip/ui/common/buttons/FloatingButton.kt @@ -0,0 +1,68 @@ +package com.texthip.thip.ui.common.buttons + +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.FloatingActionButton +import androidx.compose.material3.Icon +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.painter.Painter +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.texthip.thip.R +import com.texthip.thip.ui.theme.ThipTheme.colors + +@Composable +fun FloatingButton( + icon: Painter, + onClick: () -> Unit = { } +) { + var expanded by remember { mutableStateOf(false) } + + Box( + modifier = Modifier + .fillMaxSize() + .padding(end = 20.dp, bottom = 32.dp), + contentAlignment = Alignment.BottomEnd + ) { + // 플로팅 버튼 + FloatingActionButton( + onClick = { + expanded = !expanded + onClick() + }, + containerColor = colors.DarkGrey, + contentColor = colors.NeonGreen, + shape = CircleShape, + modifier = Modifier + .padding(16.dp) + .size(56.dp) + .border(width = 2.dp, color = colors.NeonGreen50, shape = CircleShape) + ) { + Icon( + painter = icon, + modifier = Modifier.size(24.dp), + tint = colors.NeonGreen, + contentDescription = null + ) + } + } +} + +@Preview +@Composable +private fun FloatingButtonPreview() { + FloatingButton( + icon = painterResource(id = R.drawable.ic_write), + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/texthip/thip/ui/common/buttons/GenreChipButton.kt b/app/src/main/java/com/texthip/thip/ui/common/buttons/GenreChipButton.kt new file mode 100644 index 00000000..6cd73363 --- /dev/null +++ b/app/src/main/java/com/texthip/thip/ui/common/buttons/GenreChipButton.kt @@ -0,0 +1,81 @@ +package com.texthip.thip.ui.common.buttons + +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.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Icon +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.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.texthip.thip.R +import com.texthip.thip.ui.theme.ThipTheme.colors +import com.texthip.thip.ui.theme.ThipTheme.typography + +@Composable +fun GenreChipButton( + modifier: Modifier = Modifier, + text: String, + onClick: () -> Unit = { } +) { + Box( + modifier = modifier + .border( + width = 1.dp, + color = colors.White, + shape = RoundedCornerShape(20.dp) + ) + .background(color = Color.Transparent, shape = RoundedCornerShape(12.dp)) + .padding(top = 4.dp, bottom = 4.dp, end = 8.dp, start = 12.dp) + .clickable { + onClick() + }, + contentAlignment = Alignment.Center, + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(2.dp), + ) { + Text( + text = text, + color = colors.White, + style = typography.info_r400_s12, + ) + Icon( + painter = painterResource(R.drawable.ic_x_20), + contentDescription = null, + tint = Color.Unspecified, + modifier = Modifier + .size(20.dp) + ) + } + } +} + +@Preview +@Composable +private fun GenreChipButtonPreview() { + Column( + modifier = Modifier + .fillMaxSize() + .padding(30.dp), + verticalArrangement = Arrangement.spacedBy(30.dp, Alignment.CenterVertically), + ) { + GenreChipButton( + text = stringResource(R.string.essay), + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/texthip/thip/ui/common/buttons/GroupVoteButton.kt b/app/src/main/java/com/texthip/thip/ui/common/buttons/GroupVoteButton.kt new file mode 100644 index 00000000..f30320b7 --- /dev/null +++ b/app/src/main/java/com/texthip/thip/ui/common/buttons/GroupVoteButton.kt @@ -0,0 +1,130 @@ +package com.texthip.thip.ui.common.buttons + +import androidx.compose.animation.animateColorAsState +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.animation.core.tween +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +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.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.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.texthip.thip.ui.theme.ThipTheme.colors +import com.texthip.thip.ui.theme.ThipTheme.typography + + +@Composable +fun GroupVoteButton( + options: List, + voteResults: List +) { + var selectedIndex by remember { mutableStateOf(null) } + + Column( + modifier = Modifier + .fillMaxWidth(), + verticalArrangement = Arrangement.spacedBy(12.dp) + ) { + options.forEachIndexed { index, option -> + val isSelected = selectedIndex == index + val hasVoted = selectedIndex != null + val votePercent = if (hasVoted) voteResults.getOrNull(index)?.coerceIn(0, 100) ?: 0 else 0 + + val animatedPercent by animateFloatAsState( + targetValue = votePercent / 100f, + animationSpec = tween(durationMillis = 500) + ) + + val backgroundColor by animateColorAsState( + targetValue = if (isSelected) colors.PurpleDark else colors.DarkGrey + ) + + val percentBarColor by animateColorAsState( + targetValue = if (isSelected) colors.Purple else colors.Grey02 + ) + + val textColor by animateColorAsState( + targetValue = if (isSelected) colors.NeonGreen else colors.White + ) + + val fontStyle = if (!hasVoted) typography.feedcopy_r400_s14_h20 + else typography.menu_sb600_s14_h24 + + Box( + modifier = Modifier + .fillMaxWidth() + .background(color = backgroundColor, shape = RoundedCornerShape(12.dp)) + .height(44.dp) + .clickable { + selectedIndex = if (isSelected) null else index + } + ) { + // 퍼센트 채우기 + if (hasVoted) { + Box( + modifier = Modifier + .fillMaxHeight() + .fillMaxWidth(animatedPercent) + .background( + color = percentBarColor, + shape = RoundedCornerShape(topStart = 12.dp, bottomStart = 12.dp) + ) + ) + } + + Row( + modifier = Modifier + .fillMaxSize() + .padding(horizontal = 12.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween + ) { + Text( + text = "${index + 1}. $option", + color = textColor, + style = fontStyle + ) + if (hasVoted) { + Text( + text = "${votePercent}%", + color = textColor, + style = fontStyle + ) + } + } + } + } + } +} + +@Preview +@Composable +private fun GroupVoteButtonPreview() { + val options = listOf("밥", "국수", "고기") + val results = listOf(20, 30, 50) + + Column( + modifier = Modifier.fillMaxSize() + ) { + GroupVoteButton( + options = options, + voteResults = results + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/texthip/thip/ui/common/buttons/HeaderButton.kt b/app/src/main/java/com/texthip/thip/ui/common/buttons/HeaderButton.kt new file mode 100644 index 00000000..cdff5839 --- /dev/null +++ b/app/src/main/java/com/texthip/thip/ui/common/buttons/HeaderButton.kt @@ -0,0 +1,67 @@ +package com.texthip.thip.ui.common.buttons + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +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.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.texthip.thip.R +import com.texthip.thip.ui.theme.ThipTheme.colors +import com.texthip.thip.ui.theme.ThipTheme.typography + +@Composable +fun HeaderButton( + modifier: Modifier = Modifier, + text: String, + onClick: () -> Unit = {}, +) { + var isClicked by remember { mutableStateOf(false) } + + Box( + modifier = modifier + .background( + color = if (isClicked) colors.Purple else colors.Grey02, + shape = RoundedCornerShape(20.dp) + ) + .clickable { + isClicked = !isClicked + onClick() + } + .padding(vertical = 4.dp, horizontal = 12.dp), + contentAlignment = Alignment.Center, + ) { + Text( + text = text, + style = typography.menu_sb600_s14_h24, + color = colors.White + ) + } +} + +@Preview +@Composable +private fun HeaderButtonPreview() { + Column( + modifier = Modifier.fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + HeaderButton( + text = stringResource(R.string.finish), + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/texthip/thip/ui/common/buttons/OptionChipButton.kt b/app/src/main/java/com/texthip/thip/ui/common/buttons/OptionChipButton.kt new file mode 100644 index 00000000..22069b2e --- /dev/null +++ b/app/src/main/java/com/texthip/thip/ui/common/buttons/OptionChipButton.kt @@ -0,0 +1,99 @@ +package com.texthip.thip.ui.common.buttons + +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.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +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.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.texthip.thip.R +import com.texthip.thip.ui.theme.ThipTheme.colors +import com.texthip.thip.ui.theme.ThipTheme.typography + +@Composable +fun OptionChipButton( + modifier: Modifier = Modifier, + text: String, + isFilled: Boolean = false, + onClick: () -> Unit, +) { + var isClicked by remember { mutableStateOf(false) } + + val textColor = when { + isFilled -> colors.White + isClicked -> colors.Purple + else -> colors.Grey01 + } + val backgroundColor = when { + isFilled && isClicked -> colors.Purple + isFilled -> colors.DarkGrey + else -> Color.Transparent + } + val borderColor = when { + !isFilled && isClicked -> colors.Purple + !isFilled -> colors.Grey02 + else -> Color.Transparent + } + + Box( + modifier = modifier + .background( + color = backgroundColor, + shape = RoundedCornerShape(20.dp) + ) + .border( + width = 1.dp, + color = borderColor, + shape = RoundedCornerShape(20.dp) + ) + .clickable { + isClicked = !isClicked + onClick() + } + .padding(vertical = 8.dp, horizontal = 12.dp), + contentAlignment = Alignment.Center, + ) { + Text( + text = text, + style = typography.info_r400_s12, + color = textColor + ) + } + +} + +@Preview +@Composable +private fun OptionChipButtonPreview() { + Column( + modifier = Modifier.fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(16.dp, Alignment.CenterVertically), + ) { + OptionChipButton( + text = stringResource(R.string.essay), + onClick = {} + ) + + OptionChipButton( + text = stringResource(R.string.essay), + isFilled = true, + onClick = {} + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/texthip/thip/ui/common/buttons/OutlinedButton.kt b/app/src/main/java/com/texthip/thip/ui/common/buttons/OutlinedButton.kt new file mode 100644 index 00000000..4ee3b4cc --- /dev/null +++ b/app/src/main/java/com/texthip/thip/ui/common/buttons/OutlinedButton.kt @@ -0,0 +1,99 @@ +package com.texthip.thip.ui.common.buttons + +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.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Icon +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.graphics.painter.Painter +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.texthip.thip.R +import com.texthip.thip.ui.theme.ThipTheme.colors +import com.texthip.thip.ui.theme.ThipTheme.typography + +@Composable +fun OutlinedButton( + modifier: Modifier = Modifier, + text: String, + icon: Painter? = null, + textStyle: TextStyle = typography.menu_sb600_s12_h20, + onClick: () -> Unit = {}, +) { + val hasIcon = icon != null + + Box( + modifier = modifier + .border( + width = 1.dp, + color = colors.Grey02, + shape = RoundedCornerShape(20.dp) + ) + .background(color = Color.Transparent, shape = RoundedCornerShape(12.dp)) + .clickable { + onClick() + }, + contentAlignment = Alignment.Center, + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + ) { + if (hasIcon) { + Icon( + painter = icon, + contentDescription = null, + tint = Color.Unspecified, + modifier = Modifier + .size(20.dp) + ) + } + Text( + text = text, + color = colors.Grey, + style = textStyle + ) + } + } +} + +@Preview +@Composable +private fun OutlinedButtonPreview() { + Column( + modifier = Modifier + .fillMaxSize() + .padding(30.dp), + verticalArrangement = Arrangement.spacedBy(30.dp, Alignment.CenterVertically), + ) { + OutlinedButton( + modifier = Modifier + .size(width = 68.dp, height = 28.dp), + text = stringResource(R.string.follow), + icon = painterResource(id = R.drawable.ic_reset_20), + onClick = {} + ) + + OutlinedButton( + modifier = Modifier + .size(width = 64.dp, height = 32.dp), + text = stringResource(R.string.change_book), + textStyle = typography.view_m500_s14, + onClick = {} + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/texthip/thip/ui/common/buttons/RecentSearchButton.kt b/app/src/main/java/com/texthip/thip/ui/common/buttons/RecentSearchButton.kt new file mode 100644 index 00000000..fc76e4f6 --- /dev/null +++ b/app/src/main/java/com/texthip/thip/ui/common/buttons/RecentSearchButton.kt @@ -0,0 +1,78 @@ +package com.texthip.thip.ui.common.buttons + +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.texthip.thip.R +import com.texthip.thip.ui.theme.ThipTheme.colors +import com.texthip.thip.ui.theme.ThipTheme.typography + +@Composable +fun RecentSearchButton( + modifier: Modifier = Modifier, + text: String, + onClick: () -> Unit = { } +) { + Box( + modifier = modifier + .border( + width = 1.dp, + color = colors.Grey02, + shape = RoundedCornerShape(20.dp) + ) + .padding(top = 6.dp, bottom = 6.dp, end = 8.dp, start = 12.dp) + .clickable { + onClick() + }, + contentAlignment = Alignment.Center, + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(4.dp), + ) { + Text( + text = text, + color = colors.White, + style = typography.menu_r400_s14_h24, + ) + Icon( + painter = painterResource(R.drawable.ic_x), + contentDescription = null, + tint = colors.Grey01, + modifier = Modifier + .size(24.dp) + ) + } + } +} + +@Preview +@Composable +private fun RecentSearchButtonPreview() { + Column( + modifier = Modifier + .fillMaxSize() + .padding(30.dp), + verticalArrangement = Arrangement.spacedBy(30.dp, Alignment.CenterVertically), + ) { + RecentSearchButton( + text = stringResource(R.string.recent_search), + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/texthip/thip/ui/common/buttons/ToggleSwitchButton.kt b/app/src/main/java/com/texthip/thip/ui/common/buttons/ToggleSwitchButton.kt new file mode 100644 index 00000000..97e4854b --- /dev/null +++ b/app/src/main/java/com/texthip/thip/ui/common/buttons/ToggleSwitchButton.kt @@ -0,0 +1,59 @@ +package com.texthip.thip.ui.common.buttons + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Icon +import androidx.compose.material3.Switch +import androidx.compose.material3.SwitchDefaults +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.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.texthip.thip.R +import com.texthip.thip.ui.theme.ThipTheme.colors + +@Composable +fun ToggleSwitchButton() { + var isChecked by remember { mutableStateOf(true) } + + Switch( + modifier = Modifier.padding(4.dp), + checked = isChecked, + onCheckedChange = { + isChecked = it + }, + colors = SwitchDefaults.colors( + checkedThumbColor = colors.White, + checkedTrackColor = colors.Purple, + uncheckedThumbColor = colors.White, + uncheckedTrackColor = colors.DarkGrey, + uncheckedBorderColor = Color.Transparent, + ), + thumbContent = { + Icon( + painter = painterResource(R.drawable.ic_circle), + contentDescription = null, + tint = Color.Unspecified, + ) + } + ) +} + +@Preview +@Composable +private fun ToggleSwitchButtonPreview() { + Column( + modifier = Modifier + .fillMaxSize() + .padding(30.dp) + ) { + ToggleSwitchButton() + } +} diff --git a/app/src/main/java/com/texthip/thip/ui/theme/Color.kt b/app/src/main/java/com/texthip/thip/ui/theme/Color.kt index 790516a9..3bbcdba8 100644 --- a/app/src/main/java/com/texthip/thip/ui/theme/Color.kt +++ b/app/src/main/java/com/texthip/thip/ui/theme/Color.kt @@ -13,6 +13,15 @@ val NeonGreen50 = Color(0x80A7FFB4) val Red = Color(0xFFFF9496) +val Mint = Color(0xFFA0F8E8) +val MintSub = Color(0xFF4FD9C0) +val Orange = Color(0xFFFDB770) +val OrangeSub = Color(0xFFFF8B17) +val Skyblue = Color(0xFFA1D5FF) +val SkyblueSub = Color(0xFF6DB5EE) +val Lavendar = Color(0xFFC8A5FF) +val LavendaSub = Color(0xFFA76FFF) + val PureWhite = Color(0xFFFFFFFF) val White = Color(0xFFFEFEFE) @@ -39,6 +48,14 @@ data class ThipColors( val NeonGreen: Color, val NeonGreen50: Color, val Red: Color, + val Mint: Color, + val MintSub: Color, + val Orange: Color, + val OrangeSub: Color, + val Skyblue: Color, + val SkyblueSub: Color, + val Lavendar: Color, + val LavendaSub: Color, val PureWhite: Color, val White: Color, val Grey50: Color, @@ -63,6 +80,14 @@ val defaultThipColors = ThipColors( NeonGreen = NeonGreen, NeonGreen50 = NeonGreen50, Red = Red, + Mint = Mint, + MintSub = MintSub, + Orange = Orange, + OrangeSub = OrangeSub, + Skyblue = Skyblue, + SkyblueSub = SkyblueSub, + Lavendar = Lavendar, + LavendaSub = LavendaSub, PureWhite = PureWhite, White = White, Grey50 = Grey50, diff --git a/app/src/main/res/drawable/ic_chevron.xml b/app/src/main/res/drawable/ic_chevron.xml new file mode 100644 index 00000000..b0df5e9e --- /dev/null +++ b/app/src/main/res/drawable/ic_chevron.xml @@ -0,0 +1,13 @@ + + + diff --git a/app/src/main/res/drawable/ic_circle.xml b/app/src/main/res/drawable/ic_circle.xml new file mode 100644 index 00000000..6a5e956b --- /dev/null +++ b/app/src/main/res/drawable/ic_circle.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_reset_20.xml b/app/src/main/res/drawable/ic_reset_20.xml new file mode 100644 index 00000000..b6e2066b --- /dev/null +++ b/app/src/main/res/drawable/ic_reset_20.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_x_20.xml b/app/src/main/res/drawable/ic_x_20.xml new file mode 100644 index 00000000..4dc19579 --- /dev/null +++ b/app/src/main/res/drawable/ic_x_20.xml @@ -0,0 +1,13 @@ + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 894f838d..5d5bd7c8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,5 +1,28 @@ Thip + + + 책이름을입력해주세요책이름을 + 한한강한강한강한ㅇㅇㄴㄴㅁ강 + + + + 내 피드에 추가 + + 아니오 + 글 등록 + 팔로우 + 책 변경 + 완료 + 에세이•자기계발 + 최근 검색어 + 리스트 추가하기 + 인물관계도 보기 + 기록 작성 + 투표 생성 + + 시간 전 모임 + \ No newline at end of file