From 4ef4f3b0245c453f3c06c6e5d45fb07321644fd4 Mon Sep 17 00:00:00 2001 From: jinukeu Date: Wed, 24 Jan 2024 16:10:06 +0900 Subject: [PATCH 01/21] =?UTF-8?q?feat:=20TextFieldButtonColor=20Gray=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../component/button/ClearIconButton.kt | 7 ++++- .../textfieldbutton/SusuTextFieldButton.kt | 13 +++++---- .../textfieldbutton/TextFieldButtonColor.kt | 28 +++++++++++++++++++ .../src/main/res/drawable/ic_clear.xml | 7 +++-- 4 files changed, 45 insertions(+), 10 deletions(-) diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/ClearIconButton.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/ClearIconButton.kt index f7bf518e..41bd19dd 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/ClearIconButton.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/ClearIconButton.kt @@ -3,25 +3,30 @@ package com.susu.core.designsystem.component.button import androidx.compose.foundation.Image import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.Icon 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.res.painterResource import androidx.compose.ui.unit.Dp import com.susu.core.designsystem.R +import com.susu.core.designsystem.theme.Gray30 import com.susu.core.ui.extension.susuClickable @Composable fun ClearIconButton( iconSize: Dp, + tint: Color = Gray30, onClick: () -> Unit, ) { - Image( + Icon( modifier = Modifier .clip(CircleShape) .size(iconSize) .susuClickable(onClick = onClick), painter = painterResource(id = R.drawable.ic_clear), contentDescription = "", + tint = tint, ) } diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/SusuTextFieldButton.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/SusuTextFieldButton.kt index fecf4144..75f81029 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/SusuTextFieldButton.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/SusuTextFieldButton.kt @@ -303,11 +303,11 @@ private fun InnerButtons( onClickCloseIcon: () -> Unit = {}, onClickFilledButton: () -> Unit = {}, ) { - val (innerButtonTextColor, innerButtonBackgroundColor) = with(color) { + val (innerButtonTextColor, innerButtonBackgroundColor, clearIconColor) = with(color) { when { - isFocused.not() -> (unFocusedContentColor to unFocusedBackgroundColor) - isActive || isSaved -> (activeContentColor to activeBackgroundColor) - else -> (inactiveContentColor to inactiveBackgroundColor) + isFocused.not() -> listOf(unFocusedContentColor, unFocusedBackgroundColor, activeClearIconColor) + isActive || isSaved -> listOf(activeContentColor, activeBackgroundColor, activeClearIconColor) + else -> listOf(inactiveContentColor, inactiveBackgroundColor, inactiveClearIconColor) } } @@ -317,6 +317,7 @@ private fun InnerButtons( ClearIconButton( iconSize = clearIconSize, onClick = onClickClearIcon, + tint = clearIconColor, ) } } @@ -423,7 +424,7 @@ fun TextFieldButtonPreview() { onClickButton = { isFocused = !isFocused }, showClearIcon = false, showCloseIcon = false, - color = TextFieldButtonColor.Orange, + color = TextFieldButtonColor.Gray, style = LargeTextFieldButtonStyle.height46, onClickFilledButton = { isSaved = isSaved.not() }, onClickClearIcon = { text = "" }, @@ -482,7 +483,7 @@ fun TextFieldButtonFocusedPreview() { ) { Text(text = "텍스트 길이에 딱 맞는 너비 (wrap)") SusuTextFieldWrapContentButton( - color = TextFieldButtonColor.Orange, + color = TextFieldButtonColor.Gray, text = text, onTextChange = { text = it }, placeholder = "", diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/TextFieldButtonColor.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/TextFieldButtonColor.kt index 81a2f245..576cc581 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/TextFieldButtonColor.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/TextFieldButtonColor.kt @@ -3,8 +3,11 @@ package com.susu.core.designsystem.component.textfieldbutton import androidx.compose.ui.graphics.Color import com.susu.core.designsystem.theme.Gray10 import com.susu.core.designsystem.theme.Gray100 +import com.susu.core.designsystem.theme.Gray15 import com.susu.core.designsystem.theme.Gray30 import com.susu.core.designsystem.theme.Gray40 +import com.susu.core.designsystem.theme.Gray50 +import com.susu.core.designsystem.theme.Orange10 import com.susu.core.designsystem.theme.Orange20 import com.susu.core.designsystem.theme.Orange60 @@ -38,6 +41,16 @@ enum class TextFieldButtonColor( placeholderColor = Gray30, unFocusedTextColor = Gray10, ), + Gray( + buttonColor = TextButtonInnerButtonColor.Gray, + savedBackgroundColor = Orange10, + editBackgroundColor = Gray15, + unFocusedBackgroundColor = Gray15, + unFocusedTextColor = Gray50, + editTextColor = Gray100, + savedTextColor = Gray100, + placeholderColor = Gray40, + ) } enum class TextButtonInnerButtonColor( @@ -47,6 +60,8 @@ enum class TextButtonInnerButtonColor( val activeBackgroundColor: Color, val inactiveBackgroundColor: Color, val unFocusedBackgroundColor: Color, + val activeClearIconColor: Color, + val inactiveClearIconColor: Color, val rippleColor: Color, ) { Black( @@ -56,6 +71,19 @@ enum class TextButtonInnerButtonColor( activeBackgroundColor = Gray100, inactiveBackgroundColor = Gray40, unFocusedBackgroundColor = Gray40, + activeClearIconColor = Gray30, + inactiveClearIconColor = Gray30, + rippleColor = Gray10, + ), + Gray( + activeContentColor = Gray10, + inactiveContentColor = Gray10, + unFocusedContentColor = Gray10, + activeBackgroundColor = Gray100, + inactiveBackgroundColor = Gray50, + unFocusedBackgroundColor = Gray50, + activeClearIconColor = Gray30, + inactiveClearIconColor = Gray40, rippleColor = Gray10, ), } diff --git a/core/designsystem/src/main/res/drawable/ic_clear.xml b/core/designsystem/src/main/res/drawable/ic_clear.xml index fef3a2ae..740e3cc0 100644 --- a/core/designsystem/src/main/res/drawable/ic_clear.xml +++ b/core/designsystem/src/main/res/drawable/ic_clear.xml @@ -3,10 +3,11 @@ android:height="24dp" android:viewportWidth="24" android:viewportHeight="24"> + - + From 7641e4ed21695b3751da2de6653e23f1a405b0a7 Mon Sep 17 00:00:00 2001 From: jinukeu Date: Wed, 24 Jan 2024 17:53:54 +0900 Subject: [PATCH 02/21] =?UTF-8?q?feat:=20=ED=88=AC=ED=91=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20ui?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../component/appbar/icon/RegisterText.kt | 33 +++++ core/ui/src/main/res/values/strings.xml | 1 + .../susu/feature/community/CommunityScreen.kt | 19 ++- .../navigation/CommunityNavigation.kt | 22 ++- .../community/voteadd/VoteAddScreen.kt | 136 ++++++++++++++++++ .../community/src/main/res/values/strings.xml | 7 + .../susu/feature/navigator/MainNavigator.kt | 7 + .../com/susu/feature/navigator/MainScreen.kt | 5 + 8 files changed, 228 insertions(+), 2 deletions(-) create mode 100644 core/designsystem/src/main/java/com/susu/core/designsystem/component/appbar/icon/RegisterText.kt create mode 100644 feature/community/src/main/java/com/susu/feature/community/voteadd/VoteAddScreen.kt create mode 100644 feature/community/src/main/res/values/strings.xml diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/appbar/icon/RegisterText.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/appbar/icon/RegisterText.kt new file mode 100644 index 00000000..7dbf1179 --- /dev/null +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/appbar/icon/RegisterText.kt @@ -0,0 +1,33 @@ +package com.susu.core.designsystem.component.appbar.icon + +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import com.susu.core.designsystem.R +import com.susu.core.designsystem.theme.SusuTheme +import com.susu.core.ui.extension.susuClickable + +@Composable +fun RegisterText( + modifier: Modifier = Modifier, + onClick: () -> Unit = {}, +) { + Text( + modifier = modifier.susuClickable( + rippleEnabled = false, + onClick = onClick, + ), + text = stringResource(com.susu.core.ui.R.string.word_register), + style = SusuTheme.typography.title_xxs, + ) +} + +@Preview +@Composable +fun RegisterTextPreview() { + SusuTheme { + RegisterText() + } +} diff --git a/core/ui/src/main/res/values/strings.xml b/core/ui/src/main/res/values/strings.xml index 1a97107f..e3aac96d 100644 --- a/core/ui/src/main/res/values/strings.xml +++ b/core/ui/src/main/res/values/strings.xml @@ -41,4 +41,5 @@ 아니요 연락처 메모 + 등록 diff --git a/feature/community/src/main/java/com/susu/feature/community/CommunityScreen.kt b/feature/community/src/main/java/com/susu/feature/community/CommunityScreen.kt index 5aec24c0..33e9fcce 100644 --- a/feature/community/src/main/java/com/susu/feature/community/CommunityScreen.kt +++ b/feature/community/src/main/java/com/susu/feature/community/CommunityScreen.kt @@ -7,15 +7,32 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp import com.susu.core.designsystem.theme.SusuTheme +import com.susu.core.ui.extension.susuClickable + +@Composable +fun CommunityRoute( + padding: PaddingValues, + navigateVoteAdd: () -> Unit, +) { + CommunityScreen( + padding = padding, + navigateVoteAdd = navigateVoteAdd, + ) +} @Composable fun CommunityScreen( padding: PaddingValues, + navigateVoteAdd: () -> Unit = {}, ) { Text( - modifier = Modifier.padding(padding), + modifier = Modifier + .padding(padding) + .susuClickable(onClick = navigateVoteAdd), text = "투표", + fontSize = 48.sp, ) } diff --git a/feature/community/src/main/java/com/susu/feature/community/navigation/CommunityNavigation.kt b/feature/community/src/main/java/com/susu/feature/community/navigation/CommunityNavigation.kt index e34c0538..e3758977 100644 --- a/feature/community/src/main/java/com/susu/feature/community/navigation/CommunityNavigation.kt +++ b/feature/community/src/main/java/com/susu/feature/community/navigation/CommunityNavigation.kt @@ -5,7 +5,14 @@ import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.NavOptions import androidx.navigation.compose.composable +import com.susu.core.ui.DialogToken +import com.susu.core.ui.SnackbarToken import com.susu.feature.community.CommunityScreen +import com.susu.feature.community.voteadd.VoteAddRoute + +fun NavController.navigateVoteAdd() { + navigate(CommunityRoute.voteAddRoute) +} fun NavController.navigateCommunity(navOptions: NavOptions) { navigate(CommunityRoute.route, navOptions) @@ -13,12 +20,25 @@ fun NavController.navigateCommunity(navOptions: NavOptions) { fun NavGraphBuilder.communityNavGraph( padding: PaddingValues, + navigateVoteAdd: () -> Unit, + popBackStack: () -> Unit, + onShowSnackbar: (SnackbarToken) -> Unit, + onShowDialog: (DialogToken) -> Unit, + handleException: (Throwable, () -> Unit) -> Unit, ) { composable(route = CommunityRoute.route) { - CommunityScreen(padding) + CommunityScreen( + padding = padding, + navigateVoteAdd = navigateVoteAdd, + ) + } + + composable(route = CommunityRoute.voteAddRoute) { + VoteAddRoute() } } object CommunityRoute { const val route = "community" + const val voteAddRoute = "vote-add" } diff --git a/feature/community/src/main/java/com/susu/feature/community/voteadd/VoteAddScreen.kt b/feature/community/src/main/java/com/susu/feature/community/voteadd/VoteAddScreen.kt new file mode 100644 index 00000000..9a50f341 --- /dev/null +++ b/feature/community/src/main/java/com/susu/feature/community/voteadd/VoteAddScreen.kt @@ -0,0 +1,136 @@ +package com.susu.feature.community.voteadd + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +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.imePadding +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.text.BasicTextField +import androidx.compose.foundation.verticalScroll +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.draw.clip +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.susu.core.designsystem.component.appbar.SusuDefaultAppBar +import com.susu.core.designsystem.component.appbar.icon.BackIcon +import com.susu.core.designsystem.component.appbar.icon.DeleteText +import com.susu.core.designsystem.component.appbar.icon.EditText +import com.susu.core.designsystem.component.appbar.icon.RegisterText +import com.susu.core.designsystem.component.button.FilledButtonColor +import com.susu.core.designsystem.component.button.SusuFilledButton +import com.susu.core.designsystem.component.button.XSmallButtonStyle +import com.susu.core.designsystem.component.textfield.SusuBasicTextField +import com.susu.core.designsystem.component.textfieldbutton.SusuTextFieldFillMaxButton +import com.susu.core.designsystem.component.textfieldbutton.TextFieldButtonColor +import com.susu.core.designsystem.component.textfieldbutton.style.MediumTextFieldButtonStyle +import com.susu.core.designsystem.component.textfieldbutton.style.TextFieldButtonStyle +import com.susu.core.designsystem.theme.Gray10 +import com.susu.core.designsystem.theme.Orange60 +import com.susu.core.designsystem.theme.SusuTheme +import com.susu.feature.community.R + +@Composable +fun VoteAddRoute() { + VoteAddScreen() +} + +@Composable +fun VoteAddScreen( + onClickBack: () -> Unit = {}, +) { + Column( + modifier = Modifier + .fillMaxSize() + .background(SusuTheme.colorScheme.background10), + ) { + SusuDefaultAppBar( + leftIcon = { + BackIcon( + onClick = onClickBack, + ) + }, + title = stringResource(R.string.vote_add_screen_title), + actions = { + RegisterText( + modifier = Modifier.padding(end = SusuTheme.spacing.spacing_m), + ) + }, + ) + + Column( + modifier = Modifier + .padding(SusuTheme.spacing.spacing_m) + .weight(1f, fill = false) + .verticalScroll(rememberScrollState()), + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(SusuTheme.spacing.spacing_xxxxs) + ) { + listOf("결혼식", "장례식", "돌잔치", "생일 기념일", "자유").forEach { + SusuFilledButton( + color = FilledButtonColor.Black, + style = XSmallButtonStyle.height28, + text = it, + ) + } + } + + Spacer(modifier = Modifier.size(SusuTheme.spacing.spacing_m)) + + SusuBasicTextField( + text = "", + textStyle = SusuTheme.typography.text_xxs, + maxLines = 10, + placeholder = stringResource(R.string.vote_add_screen_textfield_placeholder), + ) + + Spacer(modifier = Modifier.size(SusuTheme.spacing.spacing_xl)) + + Column( + verticalArrangement = Arrangement.spacedBy(SusuTheme.spacing.spacing_xxs) + ) { + repeat(5) { + SusuTextFieldFillMaxButton( + style = MediumTextFieldButtonStyle.height52, + color = TextFieldButtonColor.Gray, + placeholder = stringResource(R.string.vote_add_screen_textfield_button_placeholder), + ) + } + } + } + + Icon( + modifier = Modifier + .imePadding() + .clip(CircleShape) + .background(Orange60) + .padding(SusuTheme.spacing.spacing_xxxxs) + .align(Alignment.CenterHorizontally), + painter = painterResource(id = com.susu.core.designsystem.R.drawable.ic_floating_button_add), + contentDescription = stringResource(R.string.vote_add_screen_content_description_vote_add_button), + tint = Gray10, + ) + } +} + +@Preview +@Composable +fun VoteAddScreenPreview() { + SusuTheme { + VoteAddScreen() + } +} diff --git a/feature/community/src/main/res/values/strings.xml b/feature/community/src/main/res/values/strings.xml new file mode 100644 index 00000000..05144a77 --- /dev/null +++ b/feature/community/src/main/res/values/strings.xml @@ -0,0 +1,7 @@ + + + 새 투표 작성 + 투표 내용을 작성해주세요 + 선택지를 입력하세요 + 투표 추가 버튼 + diff --git a/feature/navigator/src/main/java/com/susu/feature/navigator/MainNavigator.kt b/feature/navigator/src/main/java/com/susu/feature/navigator/MainNavigator.kt index 6a2ac284..9bf079f1 100644 --- a/feature/navigator/src/main/java/com/susu/feature/navigator/MainNavigator.kt +++ b/feature/navigator/src/main/java/com/susu/feature/navigator/MainNavigator.kt @@ -10,7 +10,9 @@ import androidx.navigation.compose.rememberNavController import androidx.navigation.navOptions import com.susu.core.designsystem.theme.SusuTheme import com.susu.core.model.Ledger +import com.susu.feature.community.navigation.CommunityRoute import com.susu.feature.community.navigation.navigateCommunity +import com.susu.feature.community.navigation.navigateVoteAdd import com.susu.feature.loginsignup.navigation.LoginSignupRoute import com.susu.feature.mypage.navigation.navigateMyPage import com.susu.feature.mypage.navigation.navigateMyPageInfo @@ -58,6 +60,7 @@ internal class MainNavigator( SentRoute.sentEnvelopeRoute, SentRoute.sentEnvelopeDetailRoute, SentRoute.sentEnvelopeEditRoute, + CommunityRoute.voteAddRoute, ), -> SusuTheme.colorScheme.background10 @@ -162,6 +165,10 @@ internal class MainNavigator( navController.navigateReceivedEnvelopeEdit() } + fun navigateVoteAdd() { + navController.navigateVoteAdd() + } + fun popBackStackIfNotHome() { if (!isSameCurrentDestination(SentRoute.route)) { navController.popBackStack() diff --git a/feature/navigator/src/main/java/com/susu/feature/navigator/MainScreen.kt b/feature/navigator/src/main/java/com/susu/feature/navigator/MainScreen.kt index 2c52a1c0..de750911 100644 --- a/feature/navigator/src/main/java/com/susu/feature/navigator/MainScreen.kt +++ b/feature/navigator/src/main/java/com/susu/feature/navigator/MainScreen.kt @@ -127,6 +127,11 @@ internal fun MainScreen( communityNavGraph( padding = innerPadding, + navigateVoteAdd = navigator::navigateVoteAdd, + popBackStack = navigator::popBackStackIfNotHome, + onShowSnackbar = viewModel::onShowSnackbar, + onShowDialog = viewModel::onShowDialog, + handleException = viewModel::handleException, ) myPageNavGraph( From 598adec8bd89cdea91afab1ea0a37d057b2266b3 Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Wed, 24 Jan 2024 19:47:44 +0900 Subject: [PATCH 03/21] =?UTF-8?q?feat:=20SusuDatePicker=EC=97=90=EC=84=9C?= =?UTF-8?q?=20=ED=81=B4=EB=A6=AD=EC=9C=BC=EB=A1=9C=20=EC=84=A0=ED=83=9D=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bottomsheet/datepicker/InfiniteColumn.kt | 20 ++++++++++++- .../datepicker/SusuDatePickerBottomSheet.kt | 29 +++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/bottomsheet/datepicker/InfiniteColumn.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/bottomsheet/datepicker/InfiniteColumn.kt index 33560044..d738b431 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/component/bottomsheet/datepicker/InfiniteColumn.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/bottomsheet/datepicker/InfiniteColumn.kt @@ -27,6 +27,7 @@ import androidx.compose.ui.unit.dp import com.susu.core.designsystem.theme.Gray100 import com.susu.core.designsystem.theme.Gray30 import com.susu.core.designsystem.theme.SusuTheme +import com.susu.core.ui.extension.susuClickable @OptIn(ExperimentalFoundationApi::class) @Composable @@ -41,14 +42,16 @@ fun InfiniteColumn( textColor: Color = Gray30, selectedTextColor: Color = Gray100, onItemSelected: (index: Int, item: T) -> Unit = { _, _ -> }, + onItemClicked: (item: T) -> Unit = { }, ) { val itemHalfHeight = LocalDensity.current.run { itemHeight.toPx() / 2f } var lastSelectedIndex by remember { mutableStateOf(0) } var itemsState by remember { mutableStateOf(items) } val lazyListState = rememberLazyListState(0) val flingBehavior: FlingBehavior = rememberSnapFlingBehavior(lazyListState) + var clickedIndex: Int? by remember { mutableStateOf(null) } - LaunchedEffect(items) { + LaunchedEffect(key1 = items) { var targetIndex = items.indexOf(initialItem) targetIndex += ((Int.MAX_VALUE / 2) / items.size) * items.size itemsState = items @@ -56,6 +59,14 @@ fun InfiniteColumn( lazyListState.scrollToItem(targetIndex - 2, scrollOffset = (itemHeight.value * 0.6f).toInt()) } + LaunchedEffect(clickedIndex) { + if (clickedIndex != null) { + lastSelectedIndex = clickedIndex!! + val targetIndex = clickedIndex!! - 2 + lazyListState.animateScrollToItem(targetIndex, scrollOffset = (itemHeight.value * 0.6f).toInt()) + } + } + LazyColumn( modifier = modifier.height(itemHeight * numberOfDisplayedItems), state = lazyListState, @@ -85,6 +96,13 @@ fun InfiniteColumn( contentAlignment = Alignment.Center, ) { Text( + modifier = Modifier.susuClickable( + onClick = { + clickedIndex = i + onItemClicked(item) + }, + rippleEnabled = false, + ), text = item.toString(), style = if (lastSelectedIndex == i) { selectedTextStyle diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/bottomsheet/datepicker/SusuDatePickerBottomSheet.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/bottomsheet/datepicker/SusuDatePickerBottomSheet.kt index 4ffee172..46a59d61 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/component/bottomsheet/datepicker/SusuDatePickerBottomSheet.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/bottomsheet/datepicker/SusuDatePickerBottomSheet.kt @@ -78,6 +78,9 @@ fun SusuDatePickerBottomSheet( } onItemSelected(selectedYear, selectedMonth, selectedDay) }, + onItemClicked = { item -> + selectedYear = item.dropLast(1).toIntOrNull() ?: currentDate.year + }, ) InfiniteColumn( modifier = Modifier.width(100.dp), @@ -95,6 +98,9 @@ fun SusuDatePickerBottomSheet( } onItemSelected(selectedYear, selectedMonth, selectedDay) }, + onItemClicked = { item -> + selectedMonth = item.dropLast(1).toIntOrNull() ?: currentDate.monthValue + }, ) InfiniteColumn( modifier = Modifier.width(100.dp), @@ -106,6 +112,9 @@ fun SusuDatePickerBottomSheet( selectedDay = item.dropLast(1).toIntOrNull() ?: 1 onItemSelected(selectedYear, selectedMonth, selectedDay) }, + onItemClicked = { item -> + selectedMonth = item.dropLast(1).toIntOrNull() ?: 1 + }, ) } } @@ -234,6 +243,9 @@ fun SusuLimitDatePickerBottomSheet( selectedYear = item.dropLast(1).toIntOrNull() ?: criteriaYear onItemSelected(selectedYear, selectedMonth, selectedDay) }, + onItemClicked = { item -> + selectedYear = item.dropLast(1).toIntOrNull() ?: criteriaYear + }, ) if (monthRange.count() > 1) { InfiniteColumn( @@ -246,6 +258,9 @@ fun SusuLimitDatePickerBottomSheet( selectedMonth = item.dropLast(1).toIntOrNull() ?: criteriaMonth onItemSelected(selectedYear, selectedMonth, selectedDay) }, + onItemClicked = { item -> + selectedMonth = item.dropLast(1).toIntOrNull() ?: criteriaMonth + }, ) } else { selectedMonth = criteriaMonth @@ -276,6 +291,9 @@ fun SusuLimitDatePickerBottomSheet( selectedDay = item.dropLast(1).toIntOrNull() ?: 1 onItemSelected(selectedYear, selectedMonth, selectedDay) }, + onItemClicked = { item -> + selectedDay = item.dropLast(1).toIntOrNull() ?: 1 + }, ) } else { selectedDay = criteriaDay @@ -312,6 +330,7 @@ fun SusuYearPickerBottomSheet( cornerRadius: Dp = 24.dp, onDismissRequest: (Int) -> Unit = {}, onItemSelected: (Int) -> Unit = {}, + onItemClicked: (Int) -> Unit = {}, ) { val currentYear = remember { LocalDate.now().year } var selectedYear by remember { mutableIntStateOf(initialYear ?: currentYear) } @@ -334,6 +353,7 @@ fun SusuYearPickerBottomSheet( selectedYear = item.dropLast(1).toIntOrNull() ?: currentYear onItemSelected(selectedYear) }, + onItemClicked = { onItemClicked(it.dropLast(1).toIntOrNull() ?: currentYear) }, ) } } @@ -367,3 +387,12 @@ fun SusuLimitDatePickerBottomSheetPreview() { ) } } + +@OptIn(ExperimentalMaterial3Api::class) +@Preview +@Composable +fun SusuYearPickerBottomSheetPreview() { + SusuTheme { + SusuYearPickerBottomSheet(maximumContainerHeight = 300.dp) + } +} From fc694081a7f94d1335e9828fab4a1b13f12eba50 Mon Sep 17 00:00:00 2001 From: jinukeu Date: Wed, 24 Jan 2024 20:48:43 +0900 Subject: [PATCH 04/21] =?UTF-8?q?feat:=20=ED=88=AC=ED=91=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EB=8F=99=EC=9E=91=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../component/appbar/icon/RegisterText.kt | 10 +-- core/ui/src/main/res/values/strings.xml | 1 + .../navigation/CommunityNavigation.kt | 5 +- .../community/voteadd/VoteAddContract.kt | 29 +++++++ .../community/voteadd/VoteAddScreen.kt | 87 +++++++++++++++++-- .../community/voteadd/VoteAddViewModel.kt | 77 ++++++++++++++++ 6 files changed, 196 insertions(+), 13 deletions(-) create mode 100644 feature/community/src/main/java/com/susu/feature/community/voteadd/VoteAddContract.kt create mode 100644 feature/community/src/main/java/com/susu/feature/community/voteadd/VoteAddViewModel.kt diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/appbar/icon/RegisterText.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/appbar/icon/RegisterText.kt index 7dbf1179..8a7b4993 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/component/appbar/icon/RegisterText.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/appbar/icon/RegisterText.kt @@ -3,24 +3,24 @@ package com.susu.core.designsystem.component.appbar.icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable 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 com.susu.core.designsystem.R +import com.susu.core.designsystem.theme.Gray100 import com.susu.core.designsystem.theme.SusuTheme import com.susu.core.ui.extension.susuClickable @Composable fun RegisterText( modifier: Modifier = Modifier, - onClick: () -> Unit = {}, + color: Color = Gray100, ) { Text( - modifier = modifier.susuClickable( - rippleEnabled = false, - onClick = onClick, - ), + modifier = modifier, text = stringResource(com.susu.core.ui.R.string.word_register), style = SusuTheme.typography.title_xxs, + color = color, ) } diff --git a/core/ui/src/main/res/values/strings.xml b/core/ui/src/main/res/values/strings.xml index e3aac96d..748fd4e8 100644 --- a/core/ui/src/main/res/values/strings.xml +++ b/core/ui/src/main/res/values/strings.xml @@ -42,4 +42,5 @@ 연락처 메모 등록 + 자유 diff --git a/feature/community/src/main/java/com/susu/feature/community/navigation/CommunityNavigation.kt b/feature/community/src/main/java/com/susu/feature/community/navigation/CommunityNavigation.kt index e3758977..9822cf6d 100644 --- a/feature/community/src/main/java/com/susu/feature/community/navigation/CommunityNavigation.kt +++ b/feature/community/src/main/java/com/susu/feature/community/navigation/CommunityNavigation.kt @@ -34,7 +34,10 @@ fun NavGraphBuilder.communityNavGraph( } composable(route = CommunityRoute.voteAddRoute) { - VoteAddRoute() + VoteAddRoute( + popBackStack = popBackStack, + handleException = handleException, + ) } } diff --git a/feature/community/src/main/java/com/susu/feature/community/voteadd/VoteAddContract.kt b/feature/community/src/main/java/com/susu/feature/community/voteadd/VoteAddContract.kt new file mode 100644 index 00000000..51450600 --- /dev/null +++ b/feature/community/src/main/java/com/susu/feature/community/voteadd/VoteAddContract.kt @@ -0,0 +1,29 @@ +package com.susu.feature.community.voteadd + +import com.susu.core.model.Category +import com.susu.core.ui.base.SideEffect +import com.susu.core.ui.base.UiState +import kotlinx.collections.immutable.PersistentList +import kotlinx.collections.immutable.persistentListOf +import java.util.UUID + +data class VoteAddState( + val categoryConfigList: PersistentList = persistentListOf(), + val selectedCategory: Category = Category(), + val voteOptionStateList: PersistentList = persistentListOf(VoteOptionState(), VoteOptionState()), + val content: String = "", + val isLoading: Boolean = false, +) : UiState { + val buttonEnabled = content.length in 1 .. 50 && + voteOptionStateList.all { it.content.length in 1 ..10 } +} + +data class VoteOptionState( + val content: String = "", + val isSaved: Boolean = false, +) + +sealed interface VoteAddSideEffect : SideEffect { + data object PopBackStack : VoteAddSideEffect + data class HandleException(val throwable: Throwable, val retry: () -> Unit) : VoteAddSideEffect +} diff --git a/feature/community/src/main/java/com/susu/feature/community/voteadd/VoteAddScreen.kt b/feature/community/src/main/java/com/susu/feature/community/voteadd/VoteAddScreen.kt index 9a50f341..de95407c 100644 --- a/feature/community/src/main/java/com/susu/feature/community/voteadd/VoteAddScreen.kt +++ b/feature/community/src/main/java/com/susu/feature/community/voteadd/VoteAddScreen.kt @@ -8,6 +8,7 @@ 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.fillMaxWidth import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size @@ -18,6 +19,7 @@ import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -25,6 +27,8 @@ 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 androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.susu.core.designsystem.component.appbar.SusuDefaultAppBar import com.susu.core.designsystem.component.appbar.icon.BackIcon import com.susu.core.designsystem.component.appbar.icon.DeleteText @@ -39,18 +43,59 @@ import com.susu.core.designsystem.component.textfieldbutton.TextFieldButtonColor import com.susu.core.designsystem.component.textfieldbutton.style.MediumTextFieldButtonStyle import com.susu.core.designsystem.component.textfieldbutton.style.TextFieldButtonStyle import com.susu.core.designsystem.theme.Gray10 +import com.susu.core.designsystem.theme.Gray100 +import com.susu.core.designsystem.theme.Gray40 import com.susu.core.designsystem.theme.Orange60 import com.susu.core.designsystem.theme.SusuTheme +import com.susu.core.model.Category +import com.susu.core.ui.extension.collectWithLifecycle +import com.susu.core.ui.extension.susuClickable import com.susu.feature.community.R @Composable -fun VoteAddRoute() { - VoteAddScreen() +fun VoteAddRoute( + viewModel: VoteAddViewModel = hiltViewModel(), + popBackStack: () -> Unit, + handleException: (Throwable, () -> Unit) -> Unit, +) { + val uiState = viewModel.uiState.collectAsStateWithLifecycle().value + viewModel.sideEffect.collectWithLifecycle { sideEffect -> + when (sideEffect) { + is VoteAddSideEffect.HandleException -> handleException(sideEffect.throwable, sideEffect.retry) + VoteAddSideEffect.PopBackStack -> popBackStack() + } + } + + LaunchedEffect(key1 = Unit) { + viewModel.getCategoryConfig() + } + + VoteAddScreen( + uiState = uiState, + onClickBack = viewModel::popBackStack, + onClickRegister = {}, + onClickCategoryButton = viewModel::selectCategory, + onTextChangeContent = viewModel::updateContent, + onTextChangeOptionContent = viewModel::updateOptionContent, + onClickOptionFilledButton = viewModel::toggleOptionSavedState, + onClickOptionClearIcon = { index -> viewModel.updateOptionContent(index, "") }, + onClickOptionCloseIcon = viewModel::removeOptionState, + onClickAddOptionButton = viewModel::addOptionState, + ) } @Composable fun VoteAddScreen( + uiState: VoteAddState = VoteAddState(), onClickBack: () -> Unit = {}, + onClickRegister: () -> Unit = {}, + onClickCategoryButton: (Category) -> Unit = {}, + onTextChangeContent: (String) -> Unit = {}, + onTextChangeOptionContent: (Int, String) -> Unit = { _, _ -> }, + onClickOptionFilledButton: (Int) -> Unit = {}, + onClickOptionClearIcon: (Int) -> Unit = {}, + onClickOptionCloseIcon: (Int) -> Unit = {}, + onClickAddOptionButton: () -> Unit = {}, ) { Column( modifier = Modifier @@ -66,7 +111,14 @@ fun VoteAddScreen( title = stringResource(R.string.vote_add_screen_title), actions = { RegisterText( - modifier = Modifier.padding(end = SusuTheme.spacing.spacing_m), + modifier = Modifier + .padding(end = SusuTheme.spacing.spacing_m) + .susuClickable( + rippleEnabled = false, + runIf = uiState.buttonEnabled, + onClick = onClickRegister + ), + color = if (uiState.buttonEnabled) Gray100 else Gray40 ) }, ) @@ -80,11 +132,23 @@ fun VoteAddScreen( Row( horizontalArrangement = Arrangement.spacedBy(SusuTheme.spacing.spacing_xxxxs) ) { - listOf("결혼식", "장례식", "돌잔치", "생일 기념일", "자유").forEach { + uiState.categoryConfigList.dropLast(1).forEach { + SusuFilledButton( + color = FilledButtonColor.Black, + style = XSmallButtonStyle.height28, + text = it.name, + isActive = it == uiState.selectedCategory, + onClick = { onClickCategoryButton(it) }, + ) + } + + uiState.categoryConfigList.lastOrNull()?.let { SusuFilledButton( color = FilledButtonColor.Black, style = XSmallButtonStyle.height28, - text = it, + text = stringResource(com.susu.core.ui.R.string.word_free), + isActive = it == uiState.selectedCategory, + onClick = { onClickCategoryButton(it) }, ) } } @@ -92,7 +156,9 @@ fun VoteAddScreen( Spacer(modifier = Modifier.size(SusuTheme.spacing.spacing_m)) SusuBasicTextField( - text = "", + modifier = Modifier.fillMaxWidth(), + text = uiState.content, + onTextChange = onTextChangeContent, textStyle = SusuTheme.typography.text_xxs, maxLines = 10, placeholder = stringResource(R.string.vote_add_screen_textfield_placeholder), @@ -103,8 +169,14 @@ fun VoteAddScreen( Column( verticalArrangement = Arrangement.spacedBy(SusuTheme.spacing.spacing_xxs) ) { - repeat(5) { + uiState.voteOptionStateList.forEachIndexed { index, option -> SusuTextFieldFillMaxButton( + text = option.content, + onTextChange = { text -> onTextChangeOptionContent(index, text) }, + onClickFilledButton = { onClickOptionFilledButton(index) }, + onClickClearIcon = { onClickOptionClearIcon(index) }, + onClickCloseIcon = { onClickOptionCloseIcon(index) }, + isSaved = option.isSaved, style = MediumTextFieldButtonStyle.height52, color = TextFieldButtonColor.Gray, placeholder = stringResource(R.string.vote_add_screen_textfield_button_placeholder), @@ -117,6 +189,7 @@ fun VoteAddScreen( modifier = Modifier .imePadding() .clip(CircleShape) + .susuClickable(onClick = onClickAddOptionButton) .background(Orange60) .padding(SusuTheme.spacing.spacing_xxxxs) .align(Alignment.CenterHorizontally), diff --git a/feature/community/src/main/java/com/susu/feature/community/voteadd/VoteAddViewModel.kt b/feature/community/src/main/java/com/susu/feature/community/voteadd/VoteAddViewModel.kt new file mode 100644 index 00000000..b93018e7 --- /dev/null +++ b/feature/community/src/main/java/com/susu/feature/community/voteadd/VoteAddViewModel.kt @@ -0,0 +1,77 @@ +package com.susu.feature.community.voteadd + +import androidx.lifecycle.viewModelScope +import com.susu.core.model.Category +import com.susu.core.ui.base.BaseViewModel +import com.susu.domain.usecase.categoryconfig.GetCategoryConfigUseCase +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.collections.immutable.toPersistentList +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class VoteAddViewModel @Inject constructor( + private val getCategoryConfigUseCase: GetCategoryConfigUseCase, +) : BaseViewModel( + VoteAddState(), +) { + companion object { + private const val MIN_OPTION_COUNT = 2 + private const val MAX_OPTION_COUNT = 5 + } + + fun getCategoryConfig() = viewModelScope.launch { + if (currentState.categoryConfigList.isNotEmpty()) return@launch + + getCategoryConfigUseCase() + .onSuccess { categoryConfig -> + intent { + copy( + categoryConfigList = categoryConfig.toPersistentList(), + selectedCategory = categoryConfig.first(), + ) + } + } + } + + fun popBackStack() = postSideEffect(VoteAddSideEffect.PopBackStack) + fun selectCategory(category: Category) = intent { + copy(selectedCategory = category) + } + + fun updateContent(content: String) = intent { + copy(content = content) + } + + fun updateOptionContent(index: Int, content: String) = intent { + copy( + voteOptionStateList = voteOptionStateList.mapIndexed { voteIndex, voteOptionState -> + if (index == voteIndex) voteOptionState.copy(content = content) + else voteOptionState + }.toPersistentList() + ) + } + + fun toggleOptionSavedState(index: Int) = intent { + copy( + voteOptionStateList = voteOptionStateList.mapIndexed { voteIndex, voteOptionState -> + if (index == voteIndex) voteOptionState.copy(isSaved = voteOptionState.isSaved.not()) + else voteOptionState + }.toPersistentList() + ) + } + + fun removeOptionState(index: Int) = intent { + if (voteOptionStateList.size <= MIN_OPTION_COUNT) return@intent this + copy( + voteOptionStateList = voteOptionStateList.removeAt(index) + ) + } + + fun addOptionState() = intent { + if (voteOptionStateList.size >= MAX_OPTION_COUNT) return@intent this + copy( + voteOptionStateList = voteOptionStateList.add(VoteOptionState()) + ) + } +} From 0655e26a42a0d527ae928b2560608eb399662c78 Mon Sep 17 00:00:00 2001 From: jinukeu Date: Wed, 24 Jan 2024 21:23:42 +0900 Subject: [PATCH 05/21] =?UTF-8?q?feat:=20=ED=88=AC=ED=91=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EC=84=9C=EB=B2=84=20=EC=97=B0=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/susu/core/model/Vote.kt | 9 +++++ .../com/susu/data/data/di/RepositoryModule.kt | 7 ++++ .../data/repository/VoteRepositoryImpl.kt | 40 +++++++++++++++++++ .../com/susu/data/remote/api/VoteService.kt | 15 +++++++ .../susu/data/remote/di/ApiServiceModule.kt | 7 ++++ .../remote/model/request/CreateVoteRequest.kt | 19 +++++++++ .../remote/model/response/VoteResponse.kt | 24 +++++++++++ .../susu/domain/repository/VoteRepository.kt | 11 +++++ .../domain/usecase/vote/CreateVoteUseCase.kt | 26 ++++++++++++ .../community/voteadd/VoteAddScreen.kt | 2 +- .../community/voteadd/VoteAddViewModel.kt | 26 ++++++++++-- 11 files changed, 181 insertions(+), 5 deletions(-) create mode 100644 core/model/src/main/java/com/susu/core/model/Vote.kt create mode 100644 data/src/main/java/com/susu/data/data/repository/VoteRepositoryImpl.kt create mode 100644 data/src/main/java/com/susu/data/remote/api/VoteService.kt create mode 100644 data/src/main/java/com/susu/data/remote/model/request/CreateVoteRequest.kt create mode 100644 data/src/main/java/com/susu/data/remote/model/response/VoteResponse.kt create mode 100644 domain/src/main/java/com/susu/domain/repository/VoteRepository.kt create mode 100644 domain/src/main/java/com/susu/domain/usecase/vote/CreateVoteUseCase.kt diff --git a/core/model/src/main/java/com/susu/core/model/Vote.kt b/core/model/src/main/java/com/susu/core/model/Vote.kt new file mode 100644 index 00000000..12a6dd4a --- /dev/null +++ b/core/model/src/main/java/com/susu/core/model/Vote.kt @@ -0,0 +1,9 @@ +package com.susu.core.model + +data class Vote( + val id: Long, + val category: String, + val content: String, + val isModified: Boolean, + val optionList: List +) diff --git a/data/src/main/java/com/susu/data/data/di/RepositoryModule.kt b/data/src/main/java/com/susu/data/data/di/RepositoryModule.kt index 9eaffd4a..20cb70fa 100644 --- a/data/src/main/java/com/susu/data/data/di/RepositoryModule.kt +++ b/data/src/main/java/com/susu/data/data/di/RepositoryModule.kt @@ -9,6 +9,7 @@ import com.susu.data.data.repository.SignUpRepositoryImpl import com.susu.data.data.repository.TermRepositoryImpl import com.susu.data.data.repository.TokenRepositoryImpl import com.susu.data.data.repository.UserRepositoryImpl +import com.susu.data.data.repository.VoteRepositoryImpl import com.susu.domain.repository.CategoryConfigRepository import com.susu.domain.repository.ExcelRepository import com.susu.domain.repository.LedgerRecentSearchRepository @@ -18,6 +19,7 @@ import com.susu.domain.repository.SignUpRepository import com.susu.domain.repository.TermRepository import com.susu.domain.repository.TokenRepository import com.susu.domain.repository.UserRepository +import com.susu.domain.repository.VoteRepository import dagger.Binds import dagger.Module import dagger.hilt.InstallIn @@ -71,4 +73,9 @@ abstract class RepositoryModule { abstract fun bindExcelRepository( excelRepositoryImpl: ExcelRepositoryImpl, ): ExcelRepository + + @Binds + abstract fun bindVoteRepository( + voteRepositoryImpl: VoteRepositoryImpl, + ): VoteRepository } diff --git a/data/src/main/java/com/susu/data/data/repository/VoteRepositoryImpl.kt b/data/src/main/java/com/susu/data/data/repository/VoteRepositoryImpl.kt new file mode 100644 index 00000000..ccb8d574 --- /dev/null +++ b/data/src/main/java/com/susu/data/data/repository/VoteRepositoryImpl.kt @@ -0,0 +1,40 @@ +package com.susu.data.data.repository + +import com.susu.core.android.Dispatcher +import com.susu.core.android.SusuDispatchers +import com.susu.core.model.Category +import com.susu.core.model.Vote +import com.susu.data.local.dao.CategoryConfigDao +import com.susu.data.local.model.toEntity +import com.susu.data.local.model.toModel +import com.susu.data.remote.api.CategoryService +import com.susu.data.remote.api.VoteService +import com.susu.data.remote.model.request.CreateVoteRequest +import com.susu.data.remote.model.request.VoteOption +import com.susu.data.remote.model.response.toModel +import com.susu.domain.repository.CategoryConfigRepository +import com.susu.domain.repository.VoteRepository +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.withContext +import javax.inject.Inject + +class VoteRepositoryImpl @Inject constructor( + private val api: VoteService, +) : VoteRepository { + override suspend fun createVote( + content: String, + optionList: List, + categoryId: Int, + ): Vote = api.createVote( + createVoteRequest = CreateVoteRequest( + content = content, + optionList = optionList.mapIndexed { index, voteContent -> + VoteOption( + content = voteContent, + seq = index + 1, + ) + }, + categoryId = categoryId, + ), + ).getOrThrow().toModel() +} diff --git a/data/src/main/java/com/susu/data/remote/api/VoteService.kt b/data/src/main/java/com/susu/data/remote/api/VoteService.kt new file mode 100644 index 00000000..58c11a2c --- /dev/null +++ b/data/src/main/java/com/susu/data/remote/api/VoteService.kt @@ -0,0 +1,15 @@ +package com.susu.data.remote.api + +import com.susu.data.remote.model.request.CreateVoteRequest +import com.susu.data.remote.model.response.VoteResponse +import com.susu.data.remote.retrofit.ApiResult +import retrofit2.http.Body +import retrofit2.http.POST + +interface VoteService { + + @POST("/api/v1/votes") + suspend fun createVote( + @Body createVoteRequest: CreateVoteRequest + ): ApiResult +} diff --git a/data/src/main/java/com/susu/data/remote/di/ApiServiceModule.kt b/data/src/main/java/com/susu/data/remote/di/ApiServiceModule.kt index 5b4f7dd4..d0bd9268 100644 --- a/data/src/main/java/com/susu/data/remote/di/ApiServiceModule.kt +++ b/data/src/main/java/com/susu/data/remote/di/ApiServiceModule.kt @@ -7,6 +7,7 @@ import com.susu.data.remote.api.SignUpService import com.susu.data.remote.api.TermService import com.susu.data.remote.api.TokenService import com.susu.data.remote.api.UserService +import com.susu.data.remote.api.VoteService import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -59,4 +60,10 @@ object ApiServiceModule { fun providesUserService(retrofit: Retrofit): UserService { return retrofit.create(UserService::class.java) } + + @Singleton + @Provides + fun providesVoteService(retrofit: Retrofit): VoteService { + return retrofit.create(VoteService::class.java) + } } diff --git a/data/src/main/java/com/susu/data/remote/model/request/CreateVoteRequest.kt b/data/src/main/java/com/susu/data/remote/model/request/CreateVoteRequest.kt new file mode 100644 index 00000000..cc7713c9 --- /dev/null +++ b/data/src/main/java/com/susu/data/remote/model/request/CreateVoteRequest.kt @@ -0,0 +1,19 @@ +package com.susu.data.remote.model.request + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class CreateVoteRequest( + val content: String, + @SerialName("options") + val optionList: List, + @SerialName("postCategoryId") + val categoryId: Int +) + +@Serializable +data class VoteOption( + val content: String, + val seq: Int +) diff --git a/data/src/main/java/com/susu/data/remote/model/response/VoteResponse.kt b/data/src/main/java/com/susu/data/remote/model/response/VoteResponse.kt new file mode 100644 index 00000000..f5485f9a --- /dev/null +++ b/data/src/main/java/com/susu/data/remote/model/response/VoteResponse.kt @@ -0,0 +1,24 @@ +package com.susu.data.remote.model.response + +import com.susu.core.model.Vote +import com.susu.data.remote.model.request.VoteOption +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class VoteResponse( + val id: Long, + val category: String, + val content: String, + val isModified: Boolean, + @SerialName("options") + val optionList: List +) + +internal fun VoteResponse.toModel() = Vote( + id = id, + category = category, + content = content, + isModified = isModified, + optionList = optionList.sortedBy { it.seq }.map { it.content }, +) diff --git a/domain/src/main/java/com/susu/domain/repository/VoteRepository.kt b/domain/src/main/java/com/susu/domain/repository/VoteRepository.kt new file mode 100644 index 00000000..9de94913 --- /dev/null +++ b/domain/src/main/java/com/susu/domain/repository/VoteRepository.kt @@ -0,0 +1,11 @@ +package com.susu.domain.repository + +import com.susu.core.model.Vote + +interface VoteRepository { + suspend fun createVote( + content: String, + optionList: List, + categoryId: Int + ): Vote +} diff --git a/domain/src/main/java/com/susu/domain/usecase/vote/CreateVoteUseCase.kt b/domain/src/main/java/com/susu/domain/usecase/vote/CreateVoteUseCase.kt new file mode 100644 index 00000000..6e5efebe --- /dev/null +++ b/domain/src/main/java/com/susu/domain/usecase/vote/CreateVoteUseCase.kt @@ -0,0 +1,26 @@ +package com.susu.domain.usecase.vote + +import com.susu.core.common.runCatchingIgnoreCancelled +import com.susu.domain.repository.CategoryConfigRepository +import com.susu.domain.repository.VoteRepository +import javax.inject.Inject + +class CreateVoteUseCase @Inject constructor( + private val voteRepository: VoteRepository, +) { + suspend operator fun invoke(param: Param) = runCatchingIgnoreCancelled { + with(param) { + voteRepository.createVote( + content = content, + optionList = optionList, + categoryId = categoryId, + ) + } + } + + data class Param( + val content: String, + val optionList: List, + val categoryId: Int, + ) +} diff --git a/feature/community/src/main/java/com/susu/feature/community/voteadd/VoteAddScreen.kt b/feature/community/src/main/java/com/susu/feature/community/voteadd/VoteAddScreen.kt index de95407c..f21e8662 100644 --- a/feature/community/src/main/java/com/susu/feature/community/voteadd/VoteAddScreen.kt +++ b/feature/community/src/main/java/com/susu/feature/community/voteadd/VoteAddScreen.kt @@ -73,7 +73,7 @@ fun VoteAddRoute( VoteAddScreen( uiState = uiState, onClickBack = viewModel::popBackStack, - onClickRegister = {}, + onClickRegister = viewModel::createVote, onClickCategoryButton = viewModel::selectCategory, onTextChangeContent = viewModel::updateContent, onTextChangeOptionContent = viewModel::updateOptionContent, diff --git a/feature/community/src/main/java/com/susu/feature/community/voteadd/VoteAddViewModel.kt b/feature/community/src/main/java/com/susu/feature/community/voteadd/VoteAddViewModel.kt index b93018e7..96d077bc 100644 --- a/feature/community/src/main/java/com/susu/feature/community/voteadd/VoteAddViewModel.kt +++ b/feature/community/src/main/java/com/susu/feature/community/voteadd/VoteAddViewModel.kt @@ -4,14 +4,17 @@ import androidx.lifecycle.viewModelScope import com.susu.core.model.Category import com.susu.core.ui.base.BaseViewModel import com.susu.domain.usecase.categoryconfig.GetCategoryConfigUseCase +import com.susu.domain.usecase.vote.CreateVoteUseCase import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.collections.immutable.toPersistentList import kotlinx.coroutines.launch +import timber.log.Timber import javax.inject.Inject @HiltViewModel class VoteAddViewModel @Inject constructor( private val getCategoryConfigUseCase: GetCategoryConfigUseCase, + private val createVoteUseCase: CreateVoteUseCase, ) : BaseViewModel( VoteAddState(), ) { @@ -20,6 +23,21 @@ class VoteAddViewModel @Inject constructor( private const val MAX_OPTION_COUNT = 5 } + fun createVote() = viewModelScope.launch { + createVoteUseCase( + param = CreateVoteUseCase.Param( + content = currentState.content, + optionList = currentState.voteOptionStateList.map { it.content }, + categoryId = currentState.selectedCategory.id, + ), + ).onSuccess { + Timber.tag("테스트").d("$it") + popBackStack() + }.onFailure { + postSideEffect(VoteAddSideEffect.HandleException(it, ::createVote)) + } + } + fun getCategoryConfig() = viewModelScope.launch { if (currentState.categoryConfigList.isNotEmpty()) return@launch @@ -48,7 +66,7 @@ class VoteAddViewModel @Inject constructor( voteOptionStateList = voteOptionStateList.mapIndexed { voteIndex, voteOptionState -> if (index == voteIndex) voteOptionState.copy(content = content) else voteOptionState - }.toPersistentList() + }.toPersistentList(), ) } @@ -57,21 +75,21 @@ class VoteAddViewModel @Inject constructor( voteOptionStateList = voteOptionStateList.mapIndexed { voteIndex, voteOptionState -> if (index == voteIndex) voteOptionState.copy(isSaved = voteOptionState.isSaved.not()) else voteOptionState - }.toPersistentList() + }.toPersistentList(), ) } fun removeOptionState(index: Int) = intent { if (voteOptionStateList.size <= MIN_OPTION_COUNT) return@intent this copy( - voteOptionStateList = voteOptionStateList.removeAt(index) + voteOptionStateList = voteOptionStateList.removeAt(index), ) } fun addOptionState() = intent { if (voteOptionStateList.size >= MAX_OPTION_COUNT) return@intent this copy( - voteOptionStateList = voteOptionStateList.add(VoteOptionState()) + voteOptionStateList = voteOptionStateList.add(VoteOptionState()), ) } } From ee16e68d254dd9646f5988c65c6dd653a2a26b16 Mon Sep 17 00:00:00 2001 From: jinukeu Date: Wed, 24 Jan 2024 21:25:03 +0900 Subject: [PATCH 06/21] chore: ktlint, detekt --- .../component/appbar/icon/RegisterText.kt | 1 - .../component/button/ClearIconButton.kt | 1 - .../textfieldbutton/TextFieldButtonColor.kt | 2 +- .../src/main/java/com/susu/core/model/Vote.kt | 2 +- .../data/data/repository/VoteRepositoryImpl.kt | 9 --------- .../java/com/susu/data/remote/api/VoteService.kt | 2 +- .../remote/model/request/CreateVoteRequest.kt | 4 ++-- .../data/remote/model/response/VoteResponse.kt | 2 +- .../com/susu/domain/repository/VoteRepository.kt | 6 +++--- .../domain/usecase/vote/CreateVoteUseCase.kt | 1 - .../community/navigation/CommunityNavigation.kt | 2 ++ .../feature/community/voteadd/VoteAddContract.kt | 5 ++--- .../feature/community/voteadd/VoteAddScreen.kt | 16 ++++------------ .../community/voteadd/VoteAddViewModel.kt | 14 ++++++++++---- 14 files changed, 27 insertions(+), 40 deletions(-) diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/appbar/icon/RegisterText.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/appbar/icon/RegisterText.kt index 8a7b4993..cee6a205 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/component/appbar/icon/RegisterText.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/appbar/icon/RegisterText.kt @@ -9,7 +9,6 @@ import androidx.compose.ui.tooling.preview.Preview import com.susu.core.designsystem.R import com.susu.core.designsystem.theme.Gray100 import com.susu.core.designsystem.theme.SusuTheme -import com.susu.core.ui.extension.susuClickable @Composable fun RegisterText( diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/ClearIconButton.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/ClearIconButton.kt index 41bd19dd..fecbcee7 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/ClearIconButton.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/ClearIconButton.kt @@ -1,6 +1,5 @@ package com.susu.core.designsystem.component.button -import androidx.compose.foundation.Image import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.Icon diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/TextFieldButtonColor.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/TextFieldButtonColor.kt index 576cc581..260c0116 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/TextFieldButtonColor.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/textfieldbutton/TextFieldButtonColor.kt @@ -50,7 +50,7 @@ enum class TextFieldButtonColor( editTextColor = Gray100, savedTextColor = Gray100, placeholderColor = Gray40, - ) + ), } enum class TextButtonInnerButtonColor( diff --git a/core/model/src/main/java/com/susu/core/model/Vote.kt b/core/model/src/main/java/com/susu/core/model/Vote.kt index 12a6dd4a..30a1d535 100644 --- a/core/model/src/main/java/com/susu/core/model/Vote.kt +++ b/core/model/src/main/java/com/susu/core/model/Vote.kt @@ -5,5 +5,5 @@ data class Vote( val category: String, val content: String, val isModified: Boolean, - val optionList: List + val optionList: List, ) diff --git a/data/src/main/java/com/susu/data/data/repository/VoteRepositoryImpl.kt b/data/src/main/java/com/susu/data/data/repository/VoteRepositoryImpl.kt index ccb8d574..e55d2cda 100644 --- a/data/src/main/java/com/susu/data/data/repository/VoteRepositoryImpl.kt +++ b/data/src/main/java/com/susu/data/data/repository/VoteRepositoryImpl.kt @@ -1,21 +1,12 @@ package com.susu.data.data.repository -import com.susu.core.android.Dispatcher -import com.susu.core.android.SusuDispatchers -import com.susu.core.model.Category import com.susu.core.model.Vote -import com.susu.data.local.dao.CategoryConfigDao -import com.susu.data.local.model.toEntity import com.susu.data.local.model.toModel -import com.susu.data.remote.api.CategoryService import com.susu.data.remote.api.VoteService import com.susu.data.remote.model.request.CreateVoteRequest import com.susu.data.remote.model.request.VoteOption import com.susu.data.remote.model.response.toModel -import com.susu.domain.repository.CategoryConfigRepository import com.susu.domain.repository.VoteRepository -import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.withContext import javax.inject.Inject class VoteRepositoryImpl @Inject constructor( diff --git a/data/src/main/java/com/susu/data/remote/api/VoteService.kt b/data/src/main/java/com/susu/data/remote/api/VoteService.kt index 58c11a2c..174e096b 100644 --- a/data/src/main/java/com/susu/data/remote/api/VoteService.kt +++ b/data/src/main/java/com/susu/data/remote/api/VoteService.kt @@ -10,6 +10,6 @@ interface VoteService { @POST("/api/v1/votes") suspend fun createVote( - @Body createVoteRequest: CreateVoteRequest + @Body createVoteRequest: CreateVoteRequest, ): ApiResult } diff --git a/data/src/main/java/com/susu/data/remote/model/request/CreateVoteRequest.kt b/data/src/main/java/com/susu/data/remote/model/request/CreateVoteRequest.kt index cc7713c9..b1cb0332 100644 --- a/data/src/main/java/com/susu/data/remote/model/request/CreateVoteRequest.kt +++ b/data/src/main/java/com/susu/data/remote/model/request/CreateVoteRequest.kt @@ -9,11 +9,11 @@ data class CreateVoteRequest( @SerialName("options") val optionList: List, @SerialName("postCategoryId") - val categoryId: Int + val categoryId: Int, ) @Serializable data class VoteOption( val content: String, - val seq: Int + val seq: Int, ) diff --git a/data/src/main/java/com/susu/data/remote/model/response/VoteResponse.kt b/data/src/main/java/com/susu/data/remote/model/response/VoteResponse.kt index f5485f9a..a7d64361 100644 --- a/data/src/main/java/com/susu/data/remote/model/response/VoteResponse.kt +++ b/data/src/main/java/com/susu/data/remote/model/response/VoteResponse.kt @@ -12,7 +12,7 @@ data class VoteResponse( val content: String, val isModified: Boolean, @SerialName("options") - val optionList: List + val optionList: List, ) internal fun VoteResponse.toModel() = Vote( diff --git a/domain/src/main/java/com/susu/domain/repository/VoteRepository.kt b/domain/src/main/java/com/susu/domain/repository/VoteRepository.kt index 9de94913..c1289413 100644 --- a/domain/src/main/java/com/susu/domain/repository/VoteRepository.kt +++ b/domain/src/main/java/com/susu/domain/repository/VoteRepository.kt @@ -4,8 +4,8 @@ import com.susu.core.model.Vote interface VoteRepository { suspend fun createVote( - content: String, - optionList: List, - categoryId: Int + content: String, + optionList: List, + categoryId: Int, ): Vote } diff --git a/domain/src/main/java/com/susu/domain/usecase/vote/CreateVoteUseCase.kt b/domain/src/main/java/com/susu/domain/usecase/vote/CreateVoteUseCase.kt index 6e5efebe..efc742b3 100644 --- a/domain/src/main/java/com/susu/domain/usecase/vote/CreateVoteUseCase.kt +++ b/domain/src/main/java/com/susu/domain/usecase/vote/CreateVoteUseCase.kt @@ -1,7 +1,6 @@ package com.susu.domain.usecase.vote import com.susu.core.common.runCatchingIgnoreCancelled -import com.susu.domain.repository.CategoryConfigRepository import com.susu.domain.repository.VoteRepository import javax.inject.Inject diff --git a/feature/community/src/main/java/com/susu/feature/community/navigation/CommunityNavigation.kt b/feature/community/src/main/java/com/susu/feature/community/navigation/CommunityNavigation.kt index 9822cf6d..ec263286 100644 --- a/feature/community/src/main/java/com/susu/feature/community/navigation/CommunityNavigation.kt +++ b/feature/community/src/main/java/com/susu/feature/community/navigation/CommunityNavigation.kt @@ -22,7 +22,9 @@ fun NavGraphBuilder.communityNavGraph( padding: PaddingValues, navigateVoteAdd: () -> Unit, popBackStack: () -> Unit, + @Suppress("detekt:UnusedParameter") onShowSnackbar: (SnackbarToken) -> Unit, + @Suppress("detekt:UnusedParameter") onShowDialog: (DialogToken) -> Unit, handleException: (Throwable, () -> Unit) -> Unit, ) { diff --git a/feature/community/src/main/java/com/susu/feature/community/voteadd/VoteAddContract.kt b/feature/community/src/main/java/com/susu/feature/community/voteadd/VoteAddContract.kt index 51450600..8bc72bfe 100644 --- a/feature/community/src/main/java/com/susu/feature/community/voteadd/VoteAddContract.kt +++ b/feature/community/src/main/java/com/susu/feature/community/voteadd/VoteAddContract.kt @@ -5,7 +5,6 @@ import com.susu.core.ui.base.SideEffect import com.susu.core.ui.base.UiState import kotlinx.collections.immutable.PersistentList import kotlinx.collections.immutable.persistentListOf -import java.util.UUID data class VoteAddState( val categoryConfigList: PersistentList = persistentListOf(), @@ -14,8 +13,8 @@ data class VoteAddState( val content: String = "", val isLoading: Boolean = false, ) : UiState { - val buttonEnabled = content.length in 1 .. 50 && - voteOptionStateList.all { it.content.length in 1 ..10 } + val buttonEnabled = content.length in 1..50 && + voteOptionStateList.all { it.content.length in 1..10 } } data class VoteOptionState( diff --git a/feature/community/src/main/java/com/susu/feature/community/voteadd/VoteAddScreen.kt b/feature/community/src/main/java/com/susu/feature/community/voteadd/VoteAddScreen.kt index f21e8662..e8051d12 100644 --- a/feature/community/src/main/java/com/susu/feature/community/voteadd/VoteAddScreen.kt +++ b/feature/community/src/main/java/com/susu/feature/community/voteadd/VoteAddScreen.kt @@ -1,9 +1,7 @@ package com.susu.feature.community.voteadd -import androidx.compose.foundation.Image import androidx.compose.foundation.background 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 @@ -14,10 +12,8 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.CircleShape -import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Icon -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Alignment @@ -26,13 +22,10 @@ import androidx.compose.ui.draw.clip 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 androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.susu.core.designsystem.component.appbar.SusuDefaultAppBar import com.susu.core.designsystem.component.appbar.icon.BackIcon -import com.susu.core.designsystem.component.appbar.icon.DeleteText -import com.susu.core.designsystem.component.appbar.icon.EditText import com.susu.core.designsystem.component.appbar.icon.RegisterText import com.susu.core.designsystem.component.button.FilledButtonColor import com.susu.core.designsystem.component.button.SusuFilledButton @@ -41,7 +34,6 @@ import com.susu.core.designsystem.component.textfield.SusuBasicTextField import com.susu.core.designsystem.component.textfieldbutton.SusuTextFieldFillMaxButton import com.susu.core.designsystem.component.textfieldbutton.TextFieldButtonColor import com.susu.core.designsystem.component.textfieldbutton.style.MediumTextFieldButtonStyle -import com.susu.core.designsystem.component.textfieldbutton.style.TextFieldButtonStyle import com.susu.core.designsystem.theme.Gray10 import com.susu.core.designsystem.theme.Gray100 import com.susu.core.designsystem.theme.Gray40 @@ -116,9 +108,9 @@ fun VoteAddScreen( .susuClickable( rippleEnabled = false, runIf = uiState.buttonEnabled, - onClick = onClickRegister + onClick = onClickRegister, ), - color = if (uiState.buttonEnabled) Gray100 else Gray40 + color = if (uiState.buttonEnabled) Gray100 else Gray40, ) }, ) @@ -130,7 +122,7 @@ fun VoteAddScreen( .verticalScroll(rememberScrollState()), ) { Row( - horizontalArrangement = Arrangement.spacedBy(SusuTheme.spacing.spacing_xxxxs) + horizontalArrangement = Arrangement.spacedBy(SusuTheme.spacing.spacing_xxxxs), ) { uiState.categoryConfigList.dropLast(1).forEach { SusuFilledButton( @@ -167,7 +159,7 @@ fun VoteAddScreen( Spacer(modifier = Modifier.size(SusuTheme.spacing.spacing_xl)) Column( - verticalArrangement = Arrangement.spacedBy(SusuTheme.spacing.spacing_xxs) + verticalArrangement = Arrangement.spacedBy(SusuTheme.spacing.spacing_xxs), ) { uiState.voteOptionStateList.forEachIndexed { index, option -> SusuTextFieldFillMaxButton( diff --git a/feature/community/src/main/java/com/susu/feature/community/voteadd/VoteAddViewModel.kt b/feature/community/src/main/java/com/susu/feature/community/voteadd/VoteAddViewModel.kt index 96d077bc..4d4c24b4 100644 --- a/feature/community/src/main/java/com/susu/feature/community/voteadd/VoteAddViewModel.kt +++ b/feature/community/src/main/java/com/susu/feature/community/voteadd/VoteAddViewModel.kt @@ -64,8 +64,11 @@ class VoteAddViewModel @Inject constructor( fun updateOptionContent(index: Int, content: String) = intent { copy( voteOptionStateList = voteOptionStateList.mapIndexed { voteIndex, voteOptionState -> - if (index == voteIndex) voteOptionState.copy(content = content) - else voteOptionState + if (index == voteIndex) { + voteOptionState.copy(content = content) + } else { + voteOptionState + } }.toPersistentList(), ) } @@ -73,8 +76,11 @@ class VoteAddViewModel @Inject constructor( fun toggleOptionSavedState(index: Int) = intent { copy( voteOptionStateList = voteOptionStateList.mapIndexed { voteIndex, voteOptionState -> - if (index == voteIndex) voteOptionState.copy(isSaved = voteOptionState.isSaved.not()) - else voteOptionState + if (index == voteIndex) { + voteOptionState.copy(isSaved = voteOptionState.isSaved.not()) + } else { + voteOptionState + } }.toPersistentList(), ) } From 007e8b20f9614a4b11938377a5471aee64388136 Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Wed, 24 Jan 2024 21:43:34 +0900 Subject: [PATCH 07/21] =?UTF-8?q?feat:=20=EB=82=B4=EC=A0=95=EB=B3=B4=20?= =?UTF-8?q?=ED=8E=B8=EC=A7=91=20=EC=B6=9C=EC=83=9D=EB=85=84=EB=8F=84=20?= =?UTF-8?q?=EB=AF=B8=EC=84=A0=ED=83=9D=20=EC=98=B5=EC=85=98=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../datepicker/SusuDatePickerBottomSheet.kt | 8 ++++--- .../src/main/res/values/strings.xml | 1 + .../src/main/java/com/susu/core/ui/Consts.kt | 2 ++ core/ui/src/main/res/values/strings.xml | 1 + .../feature/mypage/info/MyPageInfoScreen.kt | 21 +++++++++++++++---- .../mypage/info/MyPageInfoViewModel.kt | 2 +- 6 files changed, 27 insertions(+), 8 deletions(-) diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/bottomsheet/datepicker/SusuDatePickerBottomSheet.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/bottomsheet/datepicker/SusuDatePickerBottomSheet.kt index 46a59d61..f75fcf1b 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/component/bottomsheet/datepicker/SusuDatePickerBottomSheet.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/bottomsheet/datepicker/SusuDatePickerBottomSheet.kt @@ -179,6 +179,7 @@ fun SusuLimitDatePickerBottomSheet( initialMonth == criteriaMonth && initialDay > criteriaDay ) -> criteriaDay + else -> initialDay }, ) @@ -334,7 +335,8 @@ fun SusuYearPickerBottomSheet( ) { val currentYear = remember { LocalDate.now().year } var selectedYear by remember { mutableIntStateOf(initialYear ?: currentYear) } - val yearList = yearRange.map { stringResource(id = R.string.word_year_format, it) }.toImmutableList() + val yearList = + (yearRange.map { stringResource(id = R.string.word_year_format, it) } + listOf(stringResource(R.string.word_not_select))).toImmutableList() SusuBottomSheet( sheetState = sheetState, containerHeight = minOf(maximumContainerHeight, itemHeight * numberOfDisplayedItems + 32.dp), @@ -350,10 +352,10 @@ fun SusuYearPickerBottomSheet( itemHeight = itemHeight, numberOfDisplayedItems = numberOfDisplayedItems, onItemSelected = { _, item -> - selectedYear = item.dropLast(1).toIntOrNull() ?: currentYear + selectedYear = item.dropLast(1).toIntOrNull() ?: 0 onItemSelected(selectedYear) }, - onItemClicked = { onItemClicked(it.dropLast(1).toIntOrNull() ?: currentYear) }, + onItemClicked = { onItemClicked(it.dropLast(1).toIntOrNull() ?: 0) }, ) } } diff --git a/core/designsystem/src/main/res/values/strings.xml b/core/designsystem/src/main/res/values/strings.xml index dbfb8c01..c30916b9 100644 --- a/core/designsystem/src/main/res/values/strings.xml +++ b/core/designsystem/src/main/res/values/strings.xml @@ -11,4 +11,5 @@ 로고 이미지 알림 아이콘 필터 아이콘 + 미선택 diff --git a/core/ui/src/main/java/com/susu/core/ui/Consts.kt b/core/ui/src/main/java/com/susu/core/ui/Consts.kt index 3df5e883..6e9175ef 100644 --- a/core/ui/src/main/java/com/susu/core/ui/Consts.kt +++ b/core/ui/src/main/java/com/susu/core/ui/Consts.kt @@ -18,6 +18,8 @@ val alignList const val USER_NAME_MAX_LENGTH = 10 val nameRegex = Regex("[a-zA-Z가-힣]{0,10}") +val USER_BIRTH_RANGE = 1930..2030 + const val INTENT_ACTION_DOWNLOAD_COMPLETE = "android.intent.action.DOWNLOAD_COMPLETE" enum class SnsProviders( diff --git a/core/ui/src/main/res/values/strings.xml b/core/ui/src/main/res/values/strings.xml index 1a97107f..df12b8c8 100644 --- a/core/ui/src/main/res/values/strings.xml +++ b/core/ui/src/main/res/values/strings.xml @@ -22,6 +22,7 @@ 더하기 버튼 닫기 아이콘 직접 입력 + 이름 성별 남성 여성 diff --git a/feature/mypage/src/main/java/com/susu/feature/mypage/info/MyPageInfoScreen.kt b/feature/mypage/src/main/java/com/susu/feature/mypage/info/MyPageInfoScreen.kt index 58b3ea01..aebf8cbe 100644 --- a/feature/mypage/src/main/java/com/susu/feature/mypage/info/MyPageInfoScreen.kt +++ b/feature/mypage/src/main/java/com/susu/feature/mypage/info/MyPageInfoScreen.kt @@ -37,9 +37,11 @@ import com.susu.core.designsystem.component.button.SusuFilledButton import com.susu.core.designsystem.component.textfield.SusuBasicTextField import com.susu.core.designsystem.theme.Gray100 import com.susu.core.designsystem.theme.Gray40 +import com.susu.core.designsystem.theme.Gray50 import com.susu.core.designsystem.theme.SusuTheme import com.susu.core.ui.Gender import com.susu.core.ui.SnackbarToken +import com.susu.core.ui.USER_BIRTH_RANGE import com.susu.core.ui.extension.collectWithLifecycle import com.susu.core.ui.extension.susuClickable import com.susu.feature.mypage.R @@ -130,7 +132,7 @@ fun MyPageInfoScreen( .padding(end = SusuTheme.spacing.spacing_m), text = stringResource(id = com.susu.core.ui.R.string.word_enrollment), style = SusuTheme.typography.title_xxs, - color = Gray100, + color = if (uiState.isEditNameValid) Gray100 else Gray50, ) } else { Text( @@ -154,7 +156,7 @@ fun MyPageInfoScreen( ) Spacer(modifier = Modifier.height(SusuTheme.spacing.spacing_m)) MyPageInfoItem( - title = "이름", + title = stringResource(id = com.susu.core.ui.R.string.word_name), ) { if (uiState.isEditing) { SusuBasicTextField( @@ -181,12 +183,23 @@ fun MyPageInfoScreen( modifier = Modifier.susuClickable( onClick = onBirthClick, ), - text = uiState.editBirth.toString(), + text = if (uiState.editBirth in USER_BIRTH_RANGE) { + uiState.editBirth.toString() + } else { + stringResource(id = com.susu.core.ui.R.string.word_not_select) + }, style = SusuTheme.typography.title_xs, color = if (uiState.birthEdited) Gray100 else Gray40, ) } else { - Text(text = uiState.userBirth.toString(), style = SusuTheme.typography.title_xs, color = Gray100) + Text( + text = if (uiState.userBirth in USER_BIRTH_RANGE) { + uiState.userBirth.toString() + } else { + stringResource(id = com.susu.core.ui.R.string.word_not_select) + }, + style = SusuTheme.typography.title_xs, color = Gray100, + ) } } MyPageInfoItem( diff --git a/feature/mypage/src/main/java/com/susu/feature/mypage/info/MyPageInfoViewModel.kt b/feature/mypage/src/main/java/com/susu/feature/mypage/info/MyPageInfoViewModel.kt index 146697ea..c2d4ae2c 100644 --- a/feature/mypage/src/main/java/com/susu/feature/mypage/info/MyPageInfoViewModel.kt +++ b/feature/mypage/src/main/java/com/susu/feature/mypage/info/MyPageInfoViewModel.kt @@ -50,7 +50,7 @@ class MyPageInfoViewModel @Inject constructor( intent { copy( isEditing = true, - editName = "", + editName = uiState.value.userName, editGender = uiState.value.userGender, editBirth = uiState.value.userBirth, ) From 09dfcb9b2e370dd2916ead4852de8e48b2d0150e Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Wed, 24 Jan 2024 22:34:02 +0900 Subject: [PATCH 08/21] =?UTF-8?q?feat:=20=EB=82=B4=EC=A0=95=EB=B3=B4=20?= =?UTF-8?q?=ED=8E=B8=EC=A7=91=20=EC=9D=B4=EB=A6=84=20=ED=98=95=EC=8B=9D=20?= =?UTF-8?q?=EB=B6=88=EB=A7=8C=EC=A1=B1=EC=8B=9C=20=EB=B6=89=EC=9D=80=20?= =?UTF-8?q?=EC=A0=90=20=ED=91=9C=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/mypage/info/MyPageInfoScreen.kt | 2 +- .../mypage/info/component/MyPageInfoItem.kt | 50 ++++++++++++++++++- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/feature/mypage/src/main/java/com/susu/feature/mypage/info/MyPageInfoScreen.kt b/feature/mypage/src/main/java/com/susu/feature/mypage/info/MyPageInfoScreen.kt index aebf8cbe..aab0f520 100644 --- a/feature/mypage/src/main/java/com/susu/feature/mypage/info/MyPageInfoScreen.kt +++ b/feature/mypage/src/main/java/com/susu/feature/mypage/info/MyPageInfoScreen.kt @@ -17,7 +17,6 @@ import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -157,6 +156,7 @@ fun MyPageInfoScreen( Spacer(modifier = Modifier.height(SusuTheme.spacing.spacing_m)) MyPageInfoItem( title = stringResource(id = com.susu.core.ui.R.string.word_name), + isWrong = uiState.isEditing && !uiState.isEditNameValid, ) { if (uiState.isEditing) { SusuBasicTextField( diff --git a/feature/mypage/src/main/java/com/susu/feature/mypage/info/component/MyPageInfoItem.kt b/feature/mypage/src/main/java/com/susu/feature/mypage/info/component/MyPageInfoItem.kt index ef0ddf2f..8567dfe8 100644 --- a/feature/mypage/src/main/java/com/susu/feature/mypage/info/component/MyPageInfoItem.kt +++ b/feature/mypage/src/main/java/com/susu/feature/mypage/info/component/MyPageInfoItem.kt @@ -2,19 +2,30 @@ package com.susu.feature.mypage.info.component import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.drawBehind +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp import com.susu.core.designsystem.theme.Gray60 +import com.susu.core.designsystem.theme.Red60 import com.susu.core.designsystem.theme.SusuTheme @Composable fun MyPageInfoItem( modifier: Modifier = Modifier, title: String = "", + isWrong: Boolean = false, content: @Composable () -> Unit, ) { Row( @@ -22,7 +33,44 @@ fun MyPageInfoItem( horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically, ) { - Text(text = title, style = SusuTheme.typography.title_xxs, color = Gray60) + Row { + Text(text = title, style = SusuTheme.typography.title_xxs, color = Gray60) + if (isWrong) { + Spacer(modifier = Modifier.width(SusuTheme.spacing.spacing_xxxxs)) + WrongDot() + } + } + content() } } + +@Composable +fun WrongDot( + modifier: Modifier = Modifier, + dotRadius: Dp = 2.dp, + color: Color = Red60, +) { + Spacer( + modifier = modifier.width(4.dp).wrapContentHeight() + .drawBehind { + drawCircle( + color = color, + radius = dotRadius.toPx(), + center = Offset(0f, 8.dp.toPx()) + ) + }, + ) +} + +@Preview +@Composable +fun MyPageInfoItemPreview() { + SusuTheme { + MyPageInfoItem( + title = "이름", + isWrong = true, + ) { + } + } +} From 3b4c1fedbc46d66f225266952cef23bcb596b378 Mon Sep 17 00:00:00 2001 From: jinukeu Date: Wed, 24 Jan 2024 23:02:27 +0900 Subject: [PATCH 09/21] =?UTF-8?q?feat:=20ClearIconButton=20tint=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../component/button/ClearIconButton.kt | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/ClearIconButton.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/ClearIconButton.kt index fecbcee7..b710b46f 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/ClearIconButton.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/ClearIconButton.kt @@ -1,5 +1,7 @@ package com.susu.core.designsystem.component.button +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.Icon @@ -8,8 +10,11 @@ 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.tooling.preview.Preview import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp import com.susu.core.designsystem.R +import com.susu.core.designsystem.theme.Gray10 import com.susu.core.designsystem.theme.Gray30 import com.susu.core.ui.extension.susuClickable @@ -22,10 +27,22 @@ fun ClearIconButton( Icon( modifier = Modifier .clip(CircleShape) + .background(tint) .size(iconSize) .susuClickable(onClick = onClick), - painter = painterResource(id = R.drawable.ic_clear), + painter = painterResource(id = com.susu.core.ui.R.drawable.ic_close), contentDescription = "", - tint = tint, + tint = Gray10, ) } + +@Preview +@Composable +fun ClearIconButtonPreview() { + Column { + ClearIconButton( + iconSize = 24.dp, + onClick = {}, + ) + } +} From a0eac97ff9928ee0ac81168b67c6b982b759b035 Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Thu, 25 Jan 2024 14:50:06 +0900 Subject: [PATCH 10/21] =?UTF-8?q?feat:=20=EB=82=B4=EC=A0=95=EB=B3=B4=20?= =?UTF-8?q?=ED=8E=B8=EC=A7=91=20=EC=9D=B4=EB=A6=84=20=ED=98=95=EC=8B=9D=20?= =?UTF-8?q?=EB=B6=88=EB=A7=8C=EC=A1=B1=20=EC=8B=9C=20=EB=93=B1=EB=A1=9D?= =?UTF-8?q?=EC=9D=84=20=EB=88=84=EB=A5=B4=EB=A9=B4=20=EC=8A=A4=EB=82=B5?= =?UTF-8?q?=EB=B0=94=20=EC=B6=9C=EB=A0=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/mypage/info/MyPageInfoContract.kt | 1 + .../susu/feature/mypage/info/MyPageInfoScreen.kt | 15 ++++++++++----- .../feature/mypage/info/MyPageInfoViewModel.kt | 5 +++++ feature/mypage/src/main/res/values/strings.xml | 1 + 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/feature/mypage/src/main/java/com/susu/feature/mypage/info/MyPageInfoContract.kt b/feature/mypage/src/main/java/com/susu/feature/mypage/info/MyPageInfoContract.kt index d5943907..b89a712a 100644 --- a/feature/mypage/src/main/java/com/susu/feature/mypage/info/MyPageInfoContract.kt +++ b/feature/mypage/src/main/java/com/susu/feature/mypage/info/MyPageInfoContract.kt @@ -7,6 +7,7 @@ import com.susu.core.ui.nameRegex sealed interface MyPageInfoEffect : SideEffect { data object PopBackStack : MyPageInfoEffect + data object ShowNameNotValidSnackBar : MyPageInfoEffect data class ShowSnackBar(val msg: String) : MyPageInfoEffect data class HandleException(val throwable: Throwable, val retry: () -> Unit) : MyPageInfoEffect } diff --git a/feature/mypage/src/main/java/com/susu/feature/mypage/info/MyPageInfoScreen.kt b/feature/mypage/src/main/java/com/susu/feature/mypage/info/MyPageInfoScreen.kt index aab0f520..450a1b27 100644 --- a/feature/mypage/src/main/java/com/susu/feature/mypage/info/MyPageInfoScreen.kt +++ b/feature/mypage/src/main/java/com/susu/feature/mypage/info/MyPageInfoScreen.kt @@ -20,6 +20,7 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign @@ -54,11 +55,16 @@ fun MyPageInfoRoute( onShowSnackbar: (SnackbarToken) -> Unit, handleException: (Throwable, () -> Unit) -> Unit, ) { + val context = LocalContext.current + viewModel.sideEffect.collectWithLifecycle { sideEffect -> when (sideEffect) { MyPageInfoEffect.PopBackStack -> popBackStack() is MyPageInfoEffect.ShowSnackBar -> onShowSnackbar(SnackbarToken(message = sideEffect.msg)) is MyPageInfoEffect.HandleException -> handleException(sideEffect.throwable, sideEffect.retry) + MyPageInfoEffect.ShowNameNotValidSnackBar -> onShowSnackbar( + SnackbarToken(message = context.getString(R.string.mypage_my_info_snackbar_invalid_name)), + ) } } @@ -124,11 +130,10 @@ fun MyPageInfoScreen( if (uiState.isEditing) { Text( modifier = Modifier + .padding(end = SusuTheme.spacing.spacing_m) .susuClickable( - runIf = uiState.isEditNameValid, onClick = onEditComplete, - ) - .padding(end = SusuTheme.spacing.spacing_m), + ), text = stringResource(id = com.susu.core.ui.R.string.word_enrollment), style = SusuTheme.typography.title_xxs, color = if (uiState.isEditNameValid) Gray100 else Gray50, @@ -136,8 +141,8 @@ fun MyPageInfoScreen( } else { Text( modifier = Modifier - .susuClickable(onClick = onEditStart) - .padding(end = SusuTheme.spacing.spacing_m), + .padding(end = SusuTheme.spacing.spacing_m) + .susuClickable(onClick = onEditStart), text = stringResource(id = com.susu.core.ui.R.string.word_edit), style = SusuTheme.typography.title_xxs, color = Gray100, diff --git a/feature/mypage/src/main/java/com/susu/feature/mypage/info/MyPageInfoViewModel.kt b/feature/mypage/src/main/java/com/susu/feature/mypage/info/MyPageInfoViewModel.kt index c2d4ae2c..bfd53849 100644 --- a/feature/mypage/src/main/java/com/susu/feature/mypage/info/MyPageInfoViewModel.kt +++ b/feature/mypage/src/main/java/com/susu/feature/mypage/info/MyPageInfoViewModel.kt @@ -78,6 +78,11 @@ class MyPageInfoViewModel @Inject constructor( } fun completeEdit() { + if (!uiState.value.isEditNameValid) { + postSideEffect(MyPageInfoEffect.ShowNameNotValidSnackBar) + return + } + viewModelScope.launch { intent { copy(isLoading = true) } patchUserUseCase(name = uiState.value.editName, gender = uiState.value.editGender.content, birth = uiState.value.editBirth) diff --git a/feature/mypage/src/main/res/values/strings.xml b/feature/mypage/src/main/res/values/strings.xml index ffc84c9c..7344015c 100644 --- a/feature/mypage/src/main/res/values/strings.xml +++ b/feature/mypage/src/main/res/values/strings.xml @@ -27,4 +27,5 @@ 로그인에 문제가 있다면 팀 옥수수에게 알려주세요 문의 남기기 프로필 이미지 + 이름은 한글 또는 영문 10글자로 입력해주세요 From 293a417a8969d88584267f846f34edf22e3e0065 Mon Sep 17 00:00:00 2001 From: jinukeu Date: Thu, 25 Jan 2024 15:57:24 +0900 Subject: [PATCH 11/21] =?UTF-8?q?feat:=20SusuButton=20-=20TextModifier,=20?= =?UTF-8?q?TextAlign=20=EC=86=8D=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../susu/core/designsystem/component/button/BasicButton.kt | 2 ++ .../core/designsystem/component/button/SusuFilledButton.kt | 6 +++++- .../core/designsystem/component/button/SusuGhostButton.kt | 6 +++++- .../core/designsystem/component/button/SusuLinedButton.kt | 7 ++++++- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/BasicButton.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/BasicButton.kt index 5cecee22..7b590248 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/BasicButton.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/BasicButton.kt @@ -28,6 +28,7 @@ import com.susu.core.ui.extension.susuClickable fun BasicButton( modifier: Modifier = Modifier, shape: Shape = RectangleShape, + textModifier: Modifier = Modifier, text: String? = null, textStyle: TextStyle = TextStyle.Default, contentColor: Color = Color.Unspecified, @@ -72,6 +73,7 @@ fun BasicButton( text?.let { Text( + modifier = textModifier, text = it, style = textStyle, color = contentColor, diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuFilledButton.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuFilledButton.kt index a01346f0..0d62e485 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuFilledButton.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuFilledButton.kt @@ -12,6 +12,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Shape 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.susu.core.designsystem.R @@ -49,6 +50,8 @@ enum class FilledButtonColor( fun SusuFilledButton( modifier: Modifier = Modifier, shape: Shape = RoundedCornerShape(4.dp), + textModifier: Modifier = Modifier, + textAlign: TextAlign = TextAlign.Unspecified, text: String? = null, color: FilledButtonColor, style: @Composable () -> ButtonStyle, @@ -63,8 +66,9 @@ fun SusuFilledButton( BasicButton( modifier = modifier, shape = shape, + textModifier = textModifier, text = text, - textStyle = textStyle, + textStyle = textStyle.copy(textAlign = textAlign), contentColor = if (isActive) activeContentColor else inactiveContentColor, rippleColor = rippleColor, backgroundColor = if (isActive) activeBackgroundColor else inactiveBackgroundColor, diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuGhostButton.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuGhostButton.kt index b372b4a1..1b904b93 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuGhostButton.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuGhostButton.kt @@ -12,6 +12,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Shape 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.susu.core.designsystem.R @@ -49,6 +50,8 @@ enum class GhostButtonColor( fun SusuGhostButton( modifier: Modifier = Modifier, shape: Shape = RoundedCornerShape(4.dp), + textModifier: Modifier = Modifier, + textAlign: TextAlign = TextAlign.Unspecified, text: String? = null, color: GhostButtonColor, style: @Composable () -> ButtonStyle, @@ -64,8 +67,9 @@ fun SusuGhostButton( BasicButton( modifier = modifier, shape = shape, + textModifier = textModifier, text = text, - textStyle = textStyle, + textStyle = textStyle.copy(textAlign = textAlign), contentColor = if (isActive) activeContentColor else inactiveContentColor, rippleColor = rippleColor, backgroundColor = if (isActive) activeBackgroundColor else inactiveBackgroundColor, diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuLinedButton.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuLinedButton.kt index caacb381..15d975b1 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuLinedButton.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuLinedButton.kt @@ -8,10 +8,12 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Icon 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.Shape 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.susu.core.designsystem.R @@ -56,6 +58,8 @@ enum class LinedButtonColor( fun SusuLinedButton( modifier: Modifier = Modifier, shape: Shape = RoundedCornerShape(4.dp), + textModifier: Modifier = Modifier, + textAlign: TextAlign = TextAlign.Unspecified, text: String? = null, color: LinedButtonColor, style: @Composable () -> ButtonStyle, @@ -70,8 +74,9 @@ fun SusuLinedButton( BasicButton( modifier = modifier, shape = shape, + textModifier = textModifier, text = text, - textStyle = textStyle, + textStyle = textStyle.copy(textAlign = textAlign), borderWidth = 1.dp, borderColor = if (isActive) activeBorderColor else inactiveBorderColor, contentColor = if (isActive) activeContentColor else inactiveContentColor, From 05315d9307403fa6685f37cf4c6aded6066862f8 Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Thu, 25 Jan 2024 16:34:13 +0900 Subject: [PATCH 12/21] =?UTF-8?q?chore:=20=EC=97=B0=EB=8F=99=EB=90=9C=20?= =?UTF-8?q?=EC=86=8C=EC=85=9C=20=EA=B3=84=EC=A0=95=20=EC=B9=B4=EC=B9=B4?= =?UTF-8?q?=EC=98=A4=ED=86=A1=EB=A7=8C=20=ED=91=9C=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 사용하지 않는 SnsProviders 삭제 --- core/ui/src/main/java/com/susu/core/ui/Consts.kt | 13 ------------- .../feature/mypage/social/MyPageSocialScreen.kt | 2 -- 2 files changed, 15 deletions(-) diff --git a/core/ui/src/main/java/com/susu/core/ui/Consts.kt b/core/ui/src/main/java/com/susu/core/ui/Consts.kt index 6e9175ef..8ff39528 100644 --- a/core/ui/src/main/java/com/susu/core/ui/Consts.kt +++ b/core/ui/src/main/java/com/susu/core/ui/Consts.kt @@ -21,7 +21,6 @@ val nameRegex = Regex("[a-zA-Z가-힣]{0,10}") val USER_BIRTH_RANGE = 1930..2030 const val INTENT_ACTION_DOWNLOAD_COMPLETE = "android.intent.action.DOWNLOAD_COMPLETE" - enum class SnsProviders( val path: String, @StringRes val nameId: Int, @@ -34,18 +33,6 @@ enum class SnsProviders( iconId = R.drawable.ic_kakao_login, backgroundColor = Color(0xFFFEE500), ), - Naver( - path = "", - nameId = R.string.sns_naver, - iconId = R.drawable.ic_kakao_login, - backgroundColor = Color.Unspecified, - ), - Google( - path = "", - nameId = R.string.sns_google, - iconId = R.drawable.ic_kakao_login, - backgroundColor = Color.Unspecified, - ), } enum class Gender(val content: String?) { diff --git a/feature/mypage/src/main/java/com/susu/feature/mypage/social/MyPageSocialScreen.kt b/feature/mypage/src/main/java/com/susu/feature/mypage/social/MyPageSocialScreen.kt index 18173e31..aeb64fc2 100644 --- a/feature/mypage/src/main/java/com/susu/feature/mypage/social/MyPageSocialScreen.kt +++ b/feature/mypage/src/main/java/com/susu/feature/mypage/social/MyPageSocialScreen.kt @@ -69,8 +69,6 @@ fun MyPageSocialScreen( SocialProvider( isActive = when (it) { SnsProviders.Kakao -> AuthApiClient.instance.hasToken() - SnsProviders.Naver -> false - SnsProviders.Google -> false }, snsProviders = it, ) From f366f6c751bb21b0b67e58c13a1693c49cb04ab4 Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Thu, 25 Jan 2024 16:46:28 +0900 Subject: [PATCH 13/21] =?UTF-8?q?feat:=20=ED=98=84=EC=9E=AC=20=EC=95=B1=20?= =?UTF-8?q?=EB=B2=84=EC=A0=84=20=ED=91=9C=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mypage/main/MyPageDefaultScreen.kt | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/feature/mypage/src/main/java/com/susu/feature/mypage/main/MyPageDefaultScreen.kt b/feature/mypage/src/main/java/com/susu/feature/mypage/main/MyPageDefaultScreen.kt index da34cbd4..684c27b5 100644 --- a/feature/mypage/src/main/java/com/susu/feature/mypage/main/MyPageDefaultScreen.kt +++ b/feature/mypage/src/main/java/com/susu/feature/mypage/main/MyPageDefaultScreen.kt @@ -1,5 +1,6 @@ package com.susu.feature.mypage.main +import android.content.Context import android.os.Environment import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box @@ -150,8 +151,11 @@ fun MyPageDefaultScreen( navigateToInfo: () -> Unit = {}, navigateToSocial: () -> Unit = {}, ) { + val context = LocalContext.current Column( - modifier = Modifier.fillMaxSize().padding(padding), + modifier = Modifier + .fillMaxSize() + .padding(padding), ) { SusuDefaultAppBar( modifier = Modifier.padding(SusuTheme.spacing.spacing_xs), @@ -218,14 +222,15 @@ fun MyPageDefaultScreen( onMenuClick = onWithdraw, ) Box( - modifier = Modifier.fillMaxWidth() + modifier = Modifier + .fillMaxWidth() .weight(1f) .background(color = Gray20) .padding(SusuTheme.spacing.spacing_m), ) { Text( modifier = Modifier.align(Alignment.TopStart), - text = stringResource(com.susu.feature.mypage.R.string.mypage_app_version) + uiState.appVersion, + text = stringResource(com.susu.feature.mypage.R.string.mypage_app_version) + " ${getAppVersion(context)}", style = SusuTheme.typography.title_xxxs, color = Gray50, ) @@ -239,6 +244,21 @@ fun MyPageDefaultScreen( } } +private fun getAppVersion(context: Context): String { + try { + val packageInfo = context.packageManager.getPackageInfo( + context.packageName, 0, + ) + + if (packageInfo != null) { + return packageInfo.versionName + } + } catch (e: Exception) { + e.printStackTrace() + } + return "" +} + @Composable fun MyPageDivider( modifier: Modifier = Modifier, From 7438e608cbbc786315779a5b947983105ebb7fde Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Thu, 25 Jan 2024 16:47:00 +0900 Subject: [PATCH 14/21] =?UTF-8?q?chore:=20=EB=A7=88=EC=9D=B4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EC=83=81=EB=8B=A8=20=EC=95=8C=EB=A6=BC=20?= =?UTF-8?q?=EC=95=84=EC=9D=B4=EC=BD=98=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/susu/feature/mypage/main/MyPageDefaultScreen.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/feature/mypage/src/main/java/com/susu/feature/mypage/main/MyPageDefaultScreen.kt b/feature/mypage/src/main/java/com/susu/feature/mypage/main/MyPageDefaultScreen.kt index 684c27b5..8118f143 100644 --- a/feature/mypage/src/main/java/com/susu/feature/mypage/main/MyPageDefaultScreen.kt +++ b/feature/mypage/src/main/java/com/susu/feature/mypage/main/MyPageDefaultScreen.kt @@ -30,7 +30,6 @@ import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.susu.core.designsystem.component.appbar.SusuDefaultAppBar import com.susu.core.designsystem.component.appbar.icon.LogoIcon -import com.susu.core.designsystem.component.appbar.icon.NotificationIcon import com.susu.core.designsystem.component.button.GhostButtonColor import com.susu.core.designsystem.component.button.SmallButtonStyle import com.susu.core.designsystem.component.button.SusuGhostButton @@ -160,7 +159,6 @@ fun MyPageDefaultScreen( SusuDefaultAppBar( modifier = Modifier.padding(SusuTheme.spacing.spacing_xs), leftIcon = { LogoIcon() }, - actions = { NotificationIcon() }, ) MyPageMenuItem( From beaa1e790a6af5cdbc333964264deeb6f6f08cb8 Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Thu, 25 Jan 2024 17:00:43 +0900 Subject: [PATCH 15/21] chore: ktlint, detekt check --- .../com/susu/feature/mypage/info/MyPageInfoScreen.kt | 3 ++- .../susu/feature/mypage/main/MyPageDefaultScreen.kt | 10 ++++++---- .../feature/mypage/main/component/MyPageMenuItem.kt | 7 ++++++- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/feature/mypage/src/main/java/com/susu/feature/mypage/info/MyPageInfoScreen.kt b/feature/mypage/src/main/java/com/susu/feature/mypage/info/MyPageInfoScreen.kt index 450a1b27..3da43baa 100644 --- a/feature/mypage/src/main/java/com/susu/feature/mypage/info/MyPageInfoScreen.kt +++ b/feature/mypage/src/main/java/com/susu/feature/mypage/info/MyPageInfoScreen.kt @@ -203,7 +203,8 @@ fun MyPageInfoScreen( } else { stringResource(id = com.susu.core.ui.R.string.word_not_select) }, - style = SusuTheme.typography.title_xs, color = Gray100, + style = SusuTheme.typography.title_xs, + color = Gray100, ) } } diff --git a/feature/mypage/src/main/java/com/susu/feature/mypage/main/MyPageDefaultScreen.kt b/feature/mypage/src/main/java/com/susu/feature/mypage/main/MyPageDefaultScreen.kt index 8118f143..73a21601 100644 --- a/feature/mypage/src/main/java/com/susu/feature/mypage/main/MyPageDefaultScreen.kt +++ b/feature/mypage/src/main/java/com/susu/feature/mypage/main/MyPageDefaultScreen.kt @@ -205,7 +205,11 @@ fun MyPageDefaultScreen( MyPageMenuItem( titleText = stringResource(com.susu.feature.mypage.R.string.mypage_app_version), action = { - Text(text = stringResource(com.susu.feature.mypage.R.string.mypage_update), style = SusuTheme.typography.title_xxs, color = Gray60) + Text( + text = stringResource(com.susu.feature.mypage.R.string.mypage_update), + style = SusuTheme.typography.title_xxs, + color = Gray60, + ) }, ) @@ -244,9 +248,7 @@ fun MyPageDefaultScreen( private fun getAppVersion(context: Context): String { try { - val packageInfo = context.packageManager.getPackageInfo( - context.packageName, 0, - ) + val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0) if (packageInfo != null) { return packageInfo.versionName diff --git a/feature/mypage/src/main/java/com/susu/feature/mypage/main/component/MyPageMenuItem.kt b/feature/mypage/src/main/java/com/susu/feature/mypage/main/component/MyPageMenuItem.kt index d928d968..9520aa05 100644 --- a/feature/mypage/src/main/java/com/susu/feature/mypage/main/component/MyPageMenuItem.kt +++ b/feature/mypage/src/main/java/com/susu/feature/mypage/main/component/MyPageMenuItem.kt @@ -40,7 +40,12 @@ fun MyPageMenuItem( .padding(padding), verticalAlignment = Alignment.CenterVertically, ) { - Text(modifier = Modifier.weight(1f), text = titleText, style = titleTextStyle, color = titleTextColor) + Text( + modifier = Modifier.weight(1f), + text = titleText, + style = titleTextStyle, + color = titleTextColor, + ) action?.let { Spacer(modifier = Modifier.width(actionItemPadding)) it() From 73f18a0a2821162c5ef1825ccb81e792a8505a9f Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Thu, 25 Jan 2024 17:09:31 +0900 Subject: [PATCH 16/21] =?UTF-8?q?refactor:=20getAppVersion=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=20runCatching=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= =?UTF-8?q?=20=EB=B0=8F=20remember=EB=A1=9C=20=ED=98=B8=EC=B6=9C=20?= =?UTF-8?q?=EC=B5=9C=EC=86=8C=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mypage/main/MyPageDefaultScreen.kt | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/feature/mypage/src/main/java/com/susu/feature/mypage/main/MyPageDefaultScreen.kt b/feature/mypage/src/main/java/com/susu/feature/mypage/main/MyPageDefaultScreen.kt index 73a21601..486d6d3b 100644 --- a/feature/mypage/src/main/java/com/susu/feature/mypage/main/MyPageDefaultScreen.kt +++ b/feature/mypage/src/main/java/com/susu/feature/mypage/main/MyPageDefaultScreen.kt @@ -17,6 +17,7 @@ import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -151,6 +152,8 @@ fun MyPageDefaultScreen( navigateToSocial: () -> Unit = {}, ) { val context = LocalContext.current + val currentAppVersion = remember { getAppVersion(context) } + Column( modifier = Modifier .fillMaxSize() @@ -232,7 +235,7 @@ fun MyPageDefaultScreen( ) { Text( modifier = Modifier.align(Alignment.TopStart), - text = stringResource(com.susu.feature.mypage.R.string.mypage_app_version) + " ${getAppVersion(context)}", + text = stringResource(com.susu.feature.mypage.R.string.mypage_app_version) + " $currentAppVersion", style = SusuTheme.typography.title_xxxs, color = Gray50, ) @@ -246,18 +249,10 @@ fun MyPageDefaultScreen( } } -private fun getAppVersion(context: Context): String { - try { - val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0) - - if (packageInfo != null) { - return packageInfo.versionName - } - } catch (e: Exception) { - e.printStackTrace() - } - return "" -} +private fun getAppVersion(context: Context): String = runCatching { + val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0) + packageInfo.versionName +}.getOrNull() ?: "" @Composable fun MyPageDivider( From 7b72345c89e3e5d7026dd3f99432c522fd106ee9 Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Thu, 25 Jan 2024 17:35:44 +0900 Subject: [PATCH 17/21] =?UTF-8?q?feat:=20=EA=B0=9C=EC=9D=B8=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EC=B2=98=EB=A6=AC=EB=B0=A9=EC=B9=A8=20=EC=9B=B9?= =?UTF-8?q?=EB=B7=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/susu/core/ui/Consts.kt | 1 + .../mypage/MyPagePrivacyPolicyScreen.kt | 26 +++++++++++++++++++ .../mypage/main/MyPageDefaultScreen.kt | 4 +++ .../mypage/navigation/MyPageNavigation.kt | 11 ++++++++ .../susu/feature/navigator/MainNavigator.kt | 5 ++++ .../com/susu/feature/navigator/MainScreen.kt | 1 + 6 files changed, 48 insertions(+) create mode 100644 feature/mypage/src/main/java/com/susu/feature/mypage/MyPagePrivacyPolicyScreen.kt diff --git a/core/ui/src/main/java/com/susu/core/ui/Consts.kt b/core/ui/src/main/java/com/susu/core/ui/Consts.kt index 8ff39528..bdfaa654 100644 --- a/core/ui/src/main/java/com/susu/core/ui/Consts.kt +++ b/core/ui/src/main/java/com/susu/core/ui/Consts.kt @@ -21,6 +21,7 @@ val nameRegex = Regex("[a-zA-Z가-힣]{0,10}") val USER_BIRTH_RANGE = 1930..2030 const val INTENT_ACTION_DOWNLOAD_COMPLETE = "android.intent.action.DOWNLOAD_COMPLETE" +const val PRIVACY_POLICY_URL = "https://sites.google.com/view/team-oksusu/%ED%99%88" enum class SnsProviders( val path: String, @StringRes val nameId: Int, diff --git a/feature/mypage/src/main/java/com/susu/feature/mypage/MyPagePrivacyPolicyScreen.kt b/feature/mypage/src/main/java/com/susu/feature/mypage/MyPagePrivacyPolicyScreen.kt new file mode 100644 index 00000000..b7962d0e --- /dev/null +++ b/feature/mypage/src/main/java/com/susu/feature/mypage/MyPagePrivacyPolicyScreen.kt @@ -0,0 +1,26 @@ +package com.susu.feature.mypage + +import android.webkit.WebView +import android.webkit.WebViewClient +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.viewinterop.AndroidView +import com.susu.core.ui.PRIVACY_POLICY_URL + +@Composable +fun MyPagePrivacyPolicyScreen( + modifier: Modifier = Modifier, +) { + AndroidView( + modifier = modifier.fillMaxSize(), + factory = { context -> + return@AndroidView WebView(context).apply { + webViewClient = WebViewClient() + } + }, + update = { + it.loadUrl(PRIVACY_POLICY_URL) + }, + ) +} diff --git a/feature/mypage/src/main/java/com/susu/feature/mypage/main/MyPageDefaultScreen.kt b/feature/mypage/src/main/java/com/susu/feature/mypage/main/MyPageDefaultScreen.kt index 486d6d3b..5d9a251a 100644 --- a/feature/mypage/src/main/java/com/susu/feature/mypage/main/MyPageDefaultScreen.kt +++ b/feature/mypage/src/main/java/com/susu/feature/mypage/main/MyPageDefaultScreen.kt @@ -53,6 +53,7 @@ fun MyPageDefaultRoute( navigateToLogin: () -> Unit, navigateToInfo: () -> Unit, navigateToSocial: () -> Unit, + navigateToPrivacyPolicy: () -> Unit, onShowSnackbar: (SnackbarToken) -> Unit, onShowDialog: (DialogToken) -> Unit, handleException: (Throwable, () -> Unit) -> Unit, @@ -138,6 +139,7 @@ fun MyPageDefaultRoute( onExport = viewModel::showExportDialog, navigateToInfo = navigateToInfo, navigateToSocial = navigateToSocial, + navigateToPrivacyPolicy = navigateToPrivacyPolicy, ) } @@ -150,6 +152,7 @@ fun MyPageDefaultScreen( onExport: () -> Unit = {}, navigateToInfo: () -> Unit = {}, navigateToSocial: () -> Unit = {}, + navigateToPrivacyPolicy: () -> Unit = {}, ) { val context = LocalContext.current val currentAppVersion = remember { getAppVersion(context) } @@ -201,6 +204,7 @@ fun MyPageDefaultScreen( ) MyPageMenuItem( titleText = stringResource(com.susu.feature.mypage.R.string.mypage_privacy_policy), + onMenuClick = navigateToPrivacyPolicy, ) MyPageDivider() diff --git a/feature/mypage/src/main/java/com/susu/feature/mypage/navigation/MyPageNavigation.kt b/feature/mypage/src/main/java/com/susu/feature/mypage/navigation/MyPageNavigation.kt index ddf1aa80..874a6dd7 100644 --- a/feature/mypage/src/main/java/com/susu/feature/mypage/navigation/MyPageNavigation.kt +++ b/feature/mypage/src/main/java/com/susu/feature/mypage/navigation/MyPageNavigation.kt @@ -7,6 +7,7 @@ import androidx.navigation.NavOptions import androidx.navigation.compose.composable import com.susu.core.ui.DialogToken import com.susu.core.ui.SnackbarToken +import com.susu.feature.mypage.MyPagePrivacyPolicyScreen import com.susu.feature.mypage.info.MyPageInfoRoute import com.susu.feature.mypage.main.MyPageDefaultRoute import com.susu.feature.mypage.social.MyPageSocialRoute @@ -23,11 +24,16 @@ fun NavController.navigateMyPageSocial() { navigate(MyPageRoute.socialRoute) } +fun NavController.navigateMyPagePrivacyPolicy() { + navigate(MyPageRoute.privacyPolicyRoute) +} + fun NavGraphBuilder.myPageNavGraph( padding: PaddingValues, navigateToLogin: () -> Unit, navigateToInfo: () -> Unit, navigateToSocial: () -> Unit, + navigateToPrivacyPolicy: () -> Unit, popBackStack: () -> Unit, onShowSnackbar: (SnackbarToken) -> Unit, onShowDialog: (DialogToken) -> Unit, @@ -39,6 +45,7 @@ fun NavGraphBuilder.myPageNavGraph( navigateToLogin = navigateToLogin, navigateToInfo = navigateToInfo, navigateToSocial = navigateToSocial, + navigateToPrivacyPolicy = navigateToPrivacyPolicy, onShowSnackbar = onShowSnackbar, onShowDialog = onShowDialog, handleException = handleException, @@ -55,10 +62,14 @@ fun NavGraphBuilder.myPageNavGraph( composable(route = MyPageRoute.socialRoute) { MyPageSocialRoute(padding = padding, popBackStack = popBackStack) } + composable(route = MyPageRoute.privacyPolicyRoute) { + MyPagePrivacyPolicyScreen() + } } object MyPageRoute { const val defaultRoute = "my-page" const val infoRoute = "info" const val socialRoute = "social" + const val privacyPolicyRoute = "privacy-policy" } diff --git a/feature/navigator/src/main/java/com/susu/feature/navigator/MainNavigator.kt b/feature/navigator/src/main/java/com/susu/feature/navigator/MainNavigator.kt index 6a2ac284..c3c2ce83 100644 --- a/feature/navigator/src/main/java/com/susu/feature/navigator/MainNavigator.kt +++ b/feature/navigator/src/main/java/com/susu/feature/navigator/MainNavigator.kt @@ -14,6 +14,7 @@ import com.susu.feature.community.navigation.navigateCommunity import com.susu.feature.loginsignup.navigation.LoginSignupRoute import com.susu.feature.mypage.navigation.navigateMyPage import com.susu.feature.mypage.navigation.navigateMyPageInfo +import com.susu.feature.mypage.navigation.navigateMyPagePrivacyPolicy import com.susu.feature.mypage.navigation.navigateMyPageSocial import com.susu.feature.received.navigation.ReceivedRoute import com.susu.feature.received.navigation.argument.FilterArgument @@ -150,6 +151,10 @@ internal class MainNavigator( navController.navigateMyPageSocial() } + fun navigateMyPagePrivacyPolicy() { + navController.navigateMyPagePrivacyPolicy() + } + fun navigateReceivedEnvelopeAdd() { navController.navigateReceivedEnvelopeAdd() } diff --git a/feature/navigator/src/main/java/com/susu/feature/navigator/MainScreen.kt b/feature/navigator/src/main/java/com/susu/feature/navigator/MainScreen.kt index 2c52a1c0..6146bc5b 100644 --- a/feature/navigator/src/main/java/com/susu/feature/navigator/MainScreen.kt +++ b/feature/navigator/src/main/java/com/susu/feature/navigator/MainScreen.kt @@ -134,6 +134,7 @@ internal fun MainScreen( navigateToLogin = navigator::navigateLogin, navigateToInfo = navigator::navigateMyPageInfo, navigateToSocial = navigator::navigateMyPageSocial, + navigateToPrivacyPolicy = navigator::navigateMyPagePrivacyPolicy, popBackStack = navigator::popBackStackIfNotHome, onShowSnackbar = viewModel::onShowSnackbar, onShowDialog = viewModel::onShowDialog, From 097664412bb8959bc715a6cdd5e9386b6f77b8d5 Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Thu, 25 Jan 2024 17:39:05 +0900 Subject: [PATCH 18/21] chore: ktlint check --- .../com/susu/feature/mypage/info/component/MyPageInfoItem.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feature/mypage/src/main/java/com/susu/feature/mypage/info/component/MyPageInfoItem.kt b/feature/mypage/src/main/java/com/susu/feature/mypage/info/component/MyPageInfoItem.kt index 8567dfe8..d6febb34 100644 --- a/feature/mypage/src/main/java/com/susu/feature/mypage/info/component/MyPageInfoItem.kt +++ b/feature/mypage/src/main/java/com/susu/feature/mypage/info/component/MyPageInfoItem.kt @@ -57,7 +57,7 @@ fun WrongDot( drawCircle( color = color, radius = dotRadius.toPx(), - center = Offset(0f, 8.dp.toPx()) + center = Offset(0f, 8.dp.toPx()), ) }, ) From 7cc107413b2720bf9afef810eacba07f93964ded Mon Sep 17 00:00:00 2001 From: jinukeu Date: Thu, 25 Jan 2024 19:23:33 +0900 Subject: [PATCH 19/21] feat: CommunityScreen ui --- .../component/button/SusuFloatingButton.kt | 8 +- core/ui/src/main/res/values/strings.xml | 1 + .../susu/feature/community/CommunityScreen.kt | 313 +++++++++++++++++- .../navigation/CommunityNavigation.kt | 3 +- .../src/main/res/drawable/ic_report.xml | 15 + .../src/main/res/drawable/ic_uncheck.xml | 9 + .../src/main/res/drawable/ic_vote.xml | 9 + .../src/main/res/drawable/ic_vote_add.xml | 9 + .../community/src/main/res/values/strings.xml | 4 + .../susu/feature/navigator/MainNavigator.kt | 1 + 10 files changed, 365 insertions(+), 7 deletions(-) create mode 100644 feature/community/src/main/res/drawable/ic_report.xml create mode 100644 feature/community/src/main/res/drawable/ic_uncheck.xml create mode 100644 feature/community/src/main/res/drawable/ic_vote.xml create mode 100644 feature/community/src/main/res/drawable/ic_vote_add.xml diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuFloatingButton.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuFloatingButton.kt index 85221062..edb3a67a 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuFloatingButton.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuFloatingButton.kt @@ -1,5 +1,6 @@ package com.susu.core.designsystem.component.button +import androidx.annotation.DrawableRes import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box @@ -12,6 +13,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.shadow 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.susu.core.designsystem.R @@ -23,6 +25,7 @@ import com.susu.core.ui.extension.susuClickable @Composable fun SusuFloatingButton( modifier: Modifier = Modifier, + @DrawableRes imageResId: Int = R.drawable.ic_floating_button_add, onClick: () -> Unit = {}, ) { Box( @@ -34,7 +37,10 @@ fun SusuFloatingButton( .susuClickable(rippleColor = Gray10, onClick = onClick), contentAlignment = Alignment.Center, ) { - Image(painter = painterResource(id = R.drawable.ic_floating_button_add), contentDescription = "추가 아이콘") + Image( + painter = painterResource(id = imageResId), + contentDescription = stringResource(id = com.susu.core.ui.R.string.content_description_add_button), + ) } } diff --git a/core/ui/src/main/res/values/strings.xml b/core/ui/src/main/res/values/strings.xml index 748fd4e8..c31e7c41 100644 --- a/core/ui/src/main/res/values/strings.xml +++ b/core/ui/src/main/res/values/strings.xml @@ -43,4 +43,5 @@ 메모 등록 자유 + 신고 버튼 diff --git a/feature/community/src/main/java/com/susu/feature/community/CommunityScreen.kt b/feature/community/src/main/java/com/susu/feature/community/CommunityScreen.kt index 33e9fcce..eed737e7 100644 --- a/feature/community/src/main/java/com/susu/feature/community/CommunityScreen.kt +++ b/feature/community/src/main/java/com/susu/feature/community/CommunityScreen.kt @@ -1,13 +1,58 @@ package com.susu.feature.community +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.horizontalScroll +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +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.size +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.HorizontalDivider +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.draw.clip +import androidx.compose.ui.draw.drawBehind +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import com.susu.core.designsystem.component.appbar.SusuDefaultAppBar +import com.susu.core.designsystem.component.appbar.icon.LogoIcon +import com.susu.core.designsystem.component.appbar.icon.NotificationIcon +import com.susu.core.designsystem.component.appbar.icon.SearchIcon +import com.susu.core.designsystem.component.button.FilledButtonColor +import com.susu.core.designsystem.component.button.GhostButtonColor +import com.susu.core.designsystem.component.button.SusuFilledButton +import com.susu.core.designsystem.component.button.SusuFloatingButton +import com.susu.core.designsystem.component.button.SusuGhostButton +import com.susu.core.designsystem.component.button.XSmallButtonStyle +import com.susu.core.designsystem.theme.Blue60 +import com.susu.core.designsystem.theme.Gray10 +import com.susu.core.designsystem.theme.Gray15 +import com.susu.core.designsystem.theme.Gray20 +import com.susu.core.designsystem.theme.Gray30 +import com.susu.core.designsystem.theme.Gray40 +import com.susu.core.designsystem.theme.Gray50 +import com.susu.core.designsystem.theme.Gray60 +import com.susu.core.designsystem.theme.Orange60 import com.susu.core.designsystem.theme.SusuTheme import com.susu.core.ui.extension.susuClickable @@ -22,18 +67,276 @@ fun CommunityRoute( ) } +@OptIn(ExperimentalFoundationApi::class) @Composable fun CommunityScreen( padding: PaddingValues, + onClickSearchIcon: () -> Unit = {}, navigateVoteAdd: () -> Unit = {}, ) { - Text( + Box( modifier = Modifier .padding(padding) - .susuClickable(onClick = navigateVoteAdd), - text = "투표", - fontSize = 48.sp, - ) + .fillMaxSize(), + ) { + Column( + modifier = Modifier + + .background(SusuTheme.colorScheme.background10), + ) { + SusuDefaultAppBar( + modifier = Modifier.padding(horizontal = SusuTheme.spacing.spacing_xs), + leftIcon = { + LogoIcon() + }, + title = stringResource(R.string.community_screen_title), + actions = { + Row { + SearchIcon(onClickSearchIcon) + } + }, + ) + + LazyColumn( + modifier = Modifier.weight(1f), + contentPadding = PaddingValues(vertical = SusuTheme.spacing.spacing_m), + ) { + item { + Column { + Text( + modifier = Modifier.padding(start = SusuTheme.spacing.spacing_m), + text = stringResource(R.string.community_screen_most_popular_vote), + style = SusuTheme.typography.title_xxs, + ) + + Spacer(modifier = Modifier.size(SusuTheme.spacing.spacing_xxs)) + + LazyRow( + contentPadding = PaddingValues(horizontal = SusuTheme.spacing.spacing_m), + horizontalArrangement = Arrangement.spacedBy(SusuTheme.spacing.spacing_m), + ) { + items(count = 5) { + Column( + modifier = Modifier + .clip(RoundedCornerShape(8.dp)) + .background(Gray15) + .size( + width = 296.dp, + height = 156.dp, + ) + .padding(SusuTheme.spacing.spacing_m), + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + ) { + Text(text = "결혼식", color = Gray60, style = SusuTheme.typography.title_xxxs) + Icon( + modifier = Modifier.size(20.dp), + painter = painterResource(id = com.susu.core.ui.R.drawable.ic_arrow_right), + contentDescription = null, + tint = Gray50, + ) + } + + Spacer(modifier = Modifier.size(SusuTheme.spacing.spacing_xxs)) + + Text( + text = "고등학교 동창이고 좀 애매하게 친한 사인데 축의금 얼마 내야 돼?", + style = SusuTheme.typography.text_xxxs, + ) + + Spacer(modifier = Modifier.size(SusuTheme.spacing.spacing_xs)) + + SusuGhostButton( + textModifier = Modifier.weight(1f), + text = "12,430명 참여 중", + textAlign = TextAlign.Center, + color = GhostButtonColor.Black, + style = XSmallButtonStyle.height44, + isClickable = false, + leftIcon = { + Image( + painter = painterResource(id = R.drawable.ic_vote), + contentDescription = null, + ) + }, + ) + } + } + } + + } + } + + item { + Spacer( + modifier = Modifier + .size(SusuTheme.spacing.spacing_m), + ) + HorizontalDivider( + thickness = SusuTheme.spacing.spacing_xxs, + color = Gray20, + ) + } + + stickyHeader { + Column( + modifier = Modifier + .background(Gray10) + .padding( + top = SusuTheme.spacing.spacing_m, + start = SusuTheme.spacing.spacing_m, + end = SusuTheme.spacing.spacing_m, + bottom = SusuTheme.spacing.spacing_xxs, + ), + verticalArrangement = Arrangement.spacedBy(SusuTheme.spacing.spacing_xl), + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(SusuTheme.spacing.spacing_xxxxs), + ) { + listOf("전체", "결혼식", "장례식", "돌잔치", "생일 기념일", "자유").forEach { + SusuFilledButton( + color = FilledButtonColor.Black, + style = XSmallButtonStyle.height28, + text = it, + isActive = true, + onClick = { }, + ) + } + } + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(SusuTheme.spacing.spacing_xxs), + ) { + Box( + modifier = Modifier + .clip(CircleShape) + .size(6.dp) + .background(Gray30), + ) + + Text( + text = stringResource(R.string.community_screen_vote_align_high), + style = SusuTheme.typography.title_xxxs, + color = Gray40, + ) + } + + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(SusuTheme.spacing.spacing_xxxxs), + ) { + Image( + painter = painterResource(id = R.drawable.ic_uncheck), + contentDescription = null, + ) + + Text( + text = stringResource(R.string.community_screen_show_my_article), + style = SusuTheme.typography.title_xxxs, + color = Gray40, + ) + } + } + } + } + + item { + Spacer(modifier = Modifier.size(SusuTheme.spacing.spacing_s)) + } + + items(10) { + Column( + modifier = Modifier + .padding( + start = SusuTheme.spacing.spacing_m, + end = SusuTheme.spacing.spacing_m, + bottom = SusuTheme.spacing.spacing_xxs, + ) + .fillMaxWidth() + .clip(RoundedCornerShape(8.dp)) + .background(Gray15) + .padding(SusuTheme.spacing.spacing_m), + ) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + ) { + Text(text = "결혼식", color = Orange60, style = SusuTheme.typography.title_xxxs) + Icon( + modifier = Modifier.size(20.dp), + painter = painterResource(id = com.susu.core.ui.R.drawable.ic_arrow_right), + contentDescription = null, + tint = Orange60, + ) + } + + Text( + text = "10분 전", + style = SusuTheme.typography.text_xxxs, + color = Gray40, + ) + } + + Spacer(modifier = Modifier.size(SusuTheme.spacing.spacing_xxs)) + + Text( + text = "고등학교 동창이고 좀 애매하게 친한 사인데 축의금 얼마 내야 돼?", + style = SusuTheme.typography.text_xxxs, + ) + + Column( + verticalArrangement = Arrangement.spacedBy(SusuTheme.spacing.spacing_xxxxs), + ) { + repeat(5) { + SusuGhostButton( + textModifier = Modifier.weight(1f), + text = "${it}만원", + color = GhostButtonColor.Black, + style = XSmallButtonStyle.height44, + isClickable = false, + ) + } + } + + Spacer(modifier = Modifier.size(SusuTheme.spacing.spacing_s)) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + ) { + Text( + text = "8명 참여", + style = SusuTheme.typography.title_xxxs, + color = Blue60, + ) + + Image( + painter = painterResource(id = R.drawable.ic_report), + contentDescription = stringResource(com.susu.core.ui.R.string.content_description_report_button), + ) + } + } + } + } + } + + SusuFloatingButton( + modifier = Modifier + .align(Alignment.BottomEnd) + .padding(SusuTheme.spacing.spacing_l), + imageResId = R.drawable.ic_vote_add, + onClick = navigateVoteAdd, + ) + } } @Preview diff --git a/feature/community/src/main/java/com/susu/feature/community/navigation/CommunityNavigation.kt b/feature/community/src/main/java/com/susu/feature/community/navigation/CommunityNavigation.kt index ec263286..3310b77f 100644 --- a/feature/community/src/main/java/com/susu/feature/community/navigation/CommunityNavigation.kt +++ b/feature/community/src/main/java/com/susu/feature/community/navigation/CommunityNavigation.kt @@ -7,6 +7,7 @@ import androidx.navigation.NavOptions import androidx.navigation.compose.composable import com.susu.core.ui.DialogToken import com.susu.core.ui.SnackbarToken +import com.susu.feature.community.CommunityRoute import com.susu.feature.community.CommunityScreen import com.susu.feature.community.voteadd.VoteAddRoute @@ -29,7 +30,7 @@ fun NavGraphBuilder.communityNavGraph( handleException: (Throwable, () -> Unit) -> Unit, ) { composable(route = CommunityRoute.route) { - CommunityScreen( + CommunityRoute( padding = padding, navigateVoteAdd = navigateVoteAdd, ) diff --git a/feature/community/src/main/res/drawable/ic_report.xml b/feature/community/src/main/res/drawable/ic_report.xml new file mode 100644 index 00000000..48c8e505 --- /dev/null +++ b/feature/community/src/main/res/drawable/ic_report.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/feature/community/src/main/res/drawable/ic_uncheck.xml b/feature/community/src/main/res/drawable/ic_uncheck.xml new file mode 100644 index 00000000..bdcd96fb --- /dev/null +++ b/feature/community/src/main/res/drawable/ic_uncheck.xml @@ -0,0 +1,9 @@ + + + diff --git a/feature/community/src/main/res/drawable/ic_vote.xml b/feature/community/src/main/res/drawable/ic_vote.xml new file mode 100644 index 00000000..49b6a3fe --- /dev/null +++ b/feature/community/src/main/res/drawable/ic_vote.xml @@ -0,0 +1,9 @@ + + + diff --git a/feature/community/src/main/res/drawable/ic_vote_add.xml b/feature/community/src/main/res/drawable/ic_vote_add.xml new file mode 100644 index 00000000..77838a10 --- /dev/null +++ b/feature/community/src/main/res/drawable/ic_vote_add.xml @@ -0,0 +1,9 @@ + + + diff --git a/feature/community/src/main/res/values/strings.xml b/feature/community/src/main/res/values/strings.xml index 05144a77..81a34cfe 100644 --- a/feature/community/src/main/res/values/strings.xml +++ b/feature/community/src/main/res/values/strings.xml @@ -4,4 +4,8 @@ 투표 내용을 작성해주세요 선택지를 입력하세요 투표 추가 버튼 + 내 글 보기 + 투표 많은 순 + 가장 인기있는 투표 + 투표 diff --git a/feature/navigator/src/main/java/com/susu/feature/navigator/MainNavigator.kt b/feature/navigator/src/main/java/com/susu/feature/navigator/MainNavigator.kt index 9bf079f1..2d6321c1 100644 --- a/feature/navigator/src/main/java/com/susu/feature/navigator/MainNavigator.kt +++ b/feature/navigator/src/main/java/com/susu/feature/navigator/MainNavigator.kt @@ -60,6 +60,7 @@ internal class MainNavigator( SentRoute.sentEnvelopeRoute, SentRoute.sentEnvelopeDetailRoute, SentRoute.sentEnvelopeEditRoute, + CommunityRoute.route, CommunityRoute.voteAddRoute, ), -> SusuTheme.colorScheme.background10 From e0145269367dbba8e504ef60bc750ccdb1140d7d Mon Sep 17 00:00:00 2001 From: jinukeu Date: Thu, 25 Jan 2024 19:32:41 +0900 Subject: [PATCH 20/21] =?UTF-8?q?feat:=20CommunityScreen=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{ => community}/CommunityScreen.kt | 134 +----------------- .../component/MostPopularVoteCard.kt | 86 +++++++++++ .../community/community/component/VoteCard.kt | 117 +++++++++++++++ .../navigation/CommunityNavigation.kt | 3 +- 4 files changed, 210 insertions(+), 130 deletions(-) rename feature/community/src/main/java/com/susu/feature/community/{ => community}/CommunityScreen.kt (56%) create mode 100644 feature/community/src/main/java/com/susu/feature/community/community/component/MostPopularVoteCard.kt create mode 100644 feature/community/src/main/java/com/susu/feature/community/community/component/VoteCard.kt diff --git a/feature/community/src/main/java/com/susu/feature/community/CommunityScreen.kt b/feature/community/src/main/java/com/susu/feature/community/community/CommunityScreen.kt similarity index 56% rename from feature/community/src/main/java/com/susu/feature/community/CommunityScreen.kt rename to feature/community/src/main/java/com/susu/feature/community/community/CommunityScreen.kt index eed737e7..576c9897 100644 --- a/feature/community/src/main/java/com/susu/feature/community/CommunityScreen.kt +++ b/feature/community/src/main/java/com/susu/feature/community/community/CommunityScreen.kt @@ -1,9 +1,8 @@ -package com.susu.feature.community +package com.susu.feature.community.community import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.Image import androidx.compose.foundation.background -import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -12,7 +11,6 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer 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.size import androidx.compose.foundation.lazy.LazyColumn @@ -26,17 +24,13 @@ 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.draw.drawBehind -import androidx.compose.ui.geometry.Offset import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import com.susu.core.designsystem.component.appbar.SusuDefaultAppBar import com.susu.core.designsystem.component.appbar.icon.LogoIcon -import com.susu.core.designsystem.component.appbar.icon.NotificationIcon import com.susu.core.designsystem.component.appbar.icon.SearchIcon import com.susu.core.designsystem.component.button.FilledButtonColor import com.susu.core.designsystem.component.button.GhostButtonColor @@ -54,7 +48,9 @@ import com.susu.core.designsystem.theme.Gray50 import com.susu.core.designsystem.theme.Gray60 import com.susu.core.designsystem.theme.Orange60 import com.susu.core.designsystem.theme.SusuTheme -import com.susu.core.ui.extension.susuClickable +import com.susu.feature.community.R +import com.susu.feature.community.community.component.MostPopularVoteCard +import com.susu.feature.community.community.component.VoteCard @Composable fun CommunityRoute( @@ -116,52 +112,7 @@ fun CommunityScreen( horizontalArrangement = Arrangement.spacedBy(SusuTheme.spacing.spacing_m), ) { items(count = 5) { - Column( - modifier = Modifier - .clip(RoundedCornerShape(8.dp)) - .background(Gray15) - .size( - width = 296.dp, - height = 156.dp, - ) - .padding(SusuTheme.spacing.spacing_m), - ) { - Row( - verticalAlignment = Alignment.CenterVertically, - ) { - Text(text = "결혼식", color = Gray60, style = SusuTheme.typography.title_xxxs) - Icon( - modifier = Modifier.size(20.dp), - painter = painterResource(id = com.susu.core.ui.R.drawable.ic_arrow_right), - contentDescription = null, - tint = Gray50, - ) - } - - Spacer(modifier = Modifier.size(SusuTheme.spacing.spacing_xxs)) - - Text( - text = "고등학교 동창이고 좀 애매하게 친한 사인데 축의금 얼마 내야 돼?", - style = SusuTheme.typography.text_xxxs, - ) - - Spacer(modifier = Modifier.size(SusuTheme.spacing.spacing_xs)) - - SusuGhostButton( - textModifier = Modifier.weight(1f), - text = "12,430명 참여 중", - textAlign = TextAlign.Center, - color = GhostButtonColor.Black, - style = XSmallButtonStyle.height44, - isClickable = false, - leftIcon = { - Image( - painter = painterResource(id = R.drawable.ic_vote), - contentDescription = null, - ) - }, - ) - } + MostPopularVoteCard() } } @@ -251,80 +202,7 @@ fun CommunityScreen( } items(10) { - Column( - modifier = Modifier - .padding( - start = SusuTheme.spacing.spacing_m, - end = SusuTheme.spacing.spacing_m, - bottom = SusuTheme.spacing.spacing_xxs, - ) - .fillMaxWidth() - .clip(RoundedCornerShape(8.dp)) - .background(Gray15) - .padding(SusuTheme.spacing.spacing_m), - ) { - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween, - ) { - Row( - verticalAlignment = Alignment.CenterVertically, - ) { - Text(text = "결혼식", color = Orange60, style = SusuTheme.typography.title_xxxs) - Icon( - modifier = Modifier.size(20.dp), - painter = painterResource(id = com.susu.core.ui.R.drawable.ic_arrow_right), - contentDescription = null, - tint = Orange60, - ) - } - - Text( - text = "10분 전", - style = SusuTheme.typography.text_xxxs, - color = Gray40, - ) - } - - Spacer(modifier = Modifier.size(SusuTheme.spacing.spacing_xxs)) - - Text( - text = "고등학교 동창이고 좀 애매하게 친한 사인데 축의금 얼마 내야 돼?", - style = SusuTheme.typography.text_xxxs, - ) - - Column( - verticalArrangement = Arrangement.spacedBy(SusuTheme.spacing.spacing_xxxxs), - ) { - repeat(5) { - SusuGhostButton( - textModifier = Modifier.weight(1f), - text = "${it}만원", - color = GhostButtonColor.Black, - style = XSmallButtonStyle.height44, - isClickable = false, - ) - } - } - - Spacer(modifier = Modifier.size(SusuTheme.spacing.spacing_s)) - - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween, - ) { - Text( - text = "8명 참여", - style = SusuTheme.typography.title_xxxs, - color = Blue60, - ) - - Image( - painter = painterResource(id = R.drawable.ic_report), - contentDescription = stringResource(com.susu.core.ui.R.string.content_description_report_button), - ) - } - } + VoteCard() } } } diff --git a/feature/community/src/main/java/com/susu/feature/community/community/component/MostPopularVoteCard.kt b/feature/community/src/main/java/com/susu/feature/community/community/component/MostPopularVoteCard.kt new file mode 100644 index 00000000..bd90867e --- /dev/null +++ b/feature/community/src/main/java/com/susu/feature/community/community/component/MostPopularVoteCard.kt @@ -0,0 +1,86 @@ +package com.susu.feature.community.community.component + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +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.draw.clip +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.susu.core.designsystem.component.button.GhostButtonColor +import com.susu.core.designsystem.component.button.SusuGhostButton +import com.susu.core.designsystem.component.button.XSmallButtonStyle +import com.susu.core.designsystem.theme.Gray15 +import com.susu.core.designsystem.theme.Gray50 +import com.susu.core.designsystem.theme.Gray60 +import com.susu.core.designsystem.theme.SusuTheme +import com.susu.feature.community.R + +@Composable +fun MostPopularVoteCard() { + Column( + modifier = Modifier + .clip(RoundedCornerShape(8.dp)) + .background(Gray15) + .size( + width = 296.dp, + height = 156.dp, + ) + .padding(SusuTheme.spacing.spacing_m), + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + ) { + Text(text = "결혼식", color = Gray60, style = SusuTheme.typography.title_xxxs) + Icon( + modifier = Modifier.size(20.dp), + painter = painterResource(id = com.susu.core.ui.R.drawable.ic_arrow_right), + contentDescription = null, + tint = Gray50, + ) + } + + Spacer(modifier = Modifier.size(SusuTheme.spacing.spacing_xxs)) + + Text( + text = "고등학교 동창이고 좀 애매하게 친한 사인데 축의금 얼마 내야 돼?", + style = SusuTheme.typography.text_xxxs, + ) + + Spacer(modifier = Modifier.size(SusuTheme.spacing.spacing_xs)) + + SusuGhostButton( + textModifier = Modifier.weight(1f), + text = "12,430명 참여 중", + textAlign = TextAlign.Center, + color = GhostButtonColor.Black, + style = XSmallButtonStyle.height44, + isClickable = false, + leftIcon = { + Image( + painter = painterResource(id = R.drawable.ic_vote), + contentDescription = null, + ) + }, + ) + } +} + +@Preview +@Composable +fun MostPopularVoteCardPreview() { + SusuTheme { + MostPopularVoteCard() + } +} diff --git a/feature/community/src/main/java/com/susu/feature/community/community/component/VoteCard.kt b/feature/community/src/main/java/com/susu/feature/community/community/component/VoteCard.kt new file mode 100644 index 00000000..ce020aef --- /dev/null +++ b/feature/community/src/main/java/com/susu/feature/community/community/component/VoteCard.kt @@ -0,0 +1,117 @@ +package com.susu.feature.community.community.component + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +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.draw.clip +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.susu.core.designsystem.component.button.GhostButtonColor +import com.susu.core.designsystem.component.button.SusuGhostButton +import com.susu.core.designsystem.component.button.XSmallButtonStyle +import com.susu.core.designsystem.theme.Blue60 +import com.susu.core.designsystem.theme.Gray15 +import com.susu.core.designsystem.theme.Gray40 +import com.susu.core.designsystem.theme.Orange60 +import com.susu.core.designsystem.theme.SusuTheme +import com.susu.feature.community.R + +@Composable +fun VoteCard() { + Column( + modifier = Modifier + .padding( + start = SusuTheme.spacing.spacing_m, + end = SusuTheme.spacing.spacing_m, + bottom = SusuTheme.spacing.spacing_xxs, + ) + .fillMaxWidth() + .clip(RoundedCornerShape(8.dp)) + .background(Gray15) + .padding(SusuTheme.spacing.spacing_m), + ) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + ) { + Text(text = "결혼식", color = Orange60, style = SusuTheme.typography.title_xxxs) + Icon( + modifier = Modifier.size(20.dp), + painter = painterResource(id = com.susu.core.ui.R.drawable.ic_arrow_right), + contentDescription = null, + tint = Orange60, + ) + } + + Text( + text = "10분 전", + style = SusuTheme.typography.text_xxxs, + color = Gray40, + ) + } + + Spacer(modifier = Modifier.size(SusuTheme.spacing.spacing_xxs)) + + Text( + text = "고등학교 동창이고 좀 애매하게 친한 사인데 축의금 얼마 내야 돼?", + style = SusuTheme.typography.text_xxxs, + ) + + Column( + verticalArrangement = Arrangement.spacedBy(SusuTheme.spacing.spacing_xxxxs), + ) { + repeat(5) { + SusuGhostButton( + textModifier = Modifier.weight(1f), + text = "${it}만원", + color = GhostButtonColor.Black, + style = XSmallButtonStyle.height44, + isClickable = false, + ) + } + } + + Spacer(modifier = Modifier.size(SusuTheme.spacing.spacing_s)) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + ) { + Text( + text = "8명 참여", + style = SusuTheme.typography.title_xxxs, + color = Blue60, + ) + + Image( + painter = painterResource(id = R.drawable.ic_report), + contentDescription = stringResource(com.susu.core.ui.R.string.content_description_report_button), + ) + } + } +} + +@Preview +@Composable +fun VoteCardPreview() { + SusuTheme { + VoteCard() + } +} diff --git a/feature/community/src/main/java/com/susu/feature/community/navigation/CommunityNavigation.kt b/feature/community/src/main/java/com/susu/feature/community/navigation/CommunityNavigation.kt index 3310b77f..5516485f 100644 --- a/feature/community/src/main/java/com/susu/feature/community/navigation/CommunityNavigation.kt +++ b/feature/community/src/main/java/com/susu/feature/community/navigation/CommunityNavigation.kt @@ -7,8 +7,7 @@ import androidx.navigation.NavOptions import androidx.navigation.compose.composable import com.susu.core.ui.DialogToken import com.susu.core.ui.SnackbarToken -import com.susu.feature.community.CommunityRoute -import com.susu.feature.community.CommunityScreen +import com.susu.feature.community.community.CommunityRoute import com.susu.feature.community.voteadd.VoteAddRoute fun NavController.navigateVoteAdd() { From 9a865256a9130a2bb10b3cb44350ce1ce748c087 Mon Sep 17 00:00:00 2001 From: jinukeu Date: Thu, 25 Jan 2024 19:33:27 +0900 Subject: [PATCH 21/21] chore: ktlint detekt --- .../designsystem/component/button/SusuLinedButton.kt | 1 - .../feature/community/community/CommunityScreen.kt | 12 ------------ 2 files changed, 13 deletions(-) diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuLinedButton.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuLinedButton.kt index 15d975b1..280815bb 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuLinedButton.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/button/SusuLinedButton.kt @@ -8,7 +8,6 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Icon 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.Shape diff --git a/feature/community/src/main/java/com/susu/feature/community/community/CommunityScreen.kt b/feature/community/src/main/java/com/susu/feature/community/community/CommunityScreen.kt index 576c9897..ec243144 100644 --- a/feature/community/src/main/java/com/susu/feature/community/community/CommunityScreen.kt +++ b/feature/community/src/main/java/com/susu/feature/community/community/CommunityScreen.kt @@ -16,9 +16,7 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.shape.CircleShape -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.HorizontalDivider -import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -26,27 +24,19 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.susu.core.designsystem.component.appbar.SusuDefaultAppBar import com.susu.core.designsystem.component.appbar.icon.LogoIcon import com.susu.core.designsystem.component.appbar.icon.SearchIcon import com.susu.core.designsystem.component.button.FilledButtonColor -import com.susu.core.designsystem.component.button.GhostButtonColor import com.susu.core.designsystem.component.button.SusuFilledButton import com.susu.core.designsystem.component.button.SusuFloatingButton -import com.susu.core.designsystem.component.button.SusuGhostButton import com.susu.core.designsystem.component.button.XSmallButtonStyle -import com.susu.core.designsystem.theme.Blue60 import com.susu.core.designsystem.theme.Gray10 -import com.susu.core.designsystem.theme.Gray15 import com.susu.core.designsystem.theme.Gray20 import com.susu.core.designsystem.theme.Gray30 import com.susu.core.designsystem.theme.Gray40 -import com.susu.core.designsystem.theme.Gray50 -import com.susu.core.designsystem.theme.Gray60 -import com.susu.core.designsystem.theme.Orange60 import com.susu.core.designsystem.theme.SusuTheme import com.susu.feature.community.R import com.susu.feature.community.community.component.MostPopularVoteCard @@ -77,7 +67,6 @@ fun CommunityScreen( ) { Column( modifier = Modifier - .background(SusuTheme.colorScheme.background10), ) { SusuDefaultAppBar( @@ -115,7 +104,6 @@ fun CommunityScreen( MostPopularVoteCard() } } - } }