From bfe6e8f79dcad1d86c7baac14549ca8a603f2ce5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=B5=E1=86=B7=E1=84=8C=E1=85=B5=E1=86=AB?= =?UTF-8?q?=E1=84=8B=E1=85=AE?= Date: Thu, 1 May 2025 00:52:11 +0900 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20=EC=BA=98=EB=A6=B0=EB=8D=94=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DateRoadDatePickerBottomSheet.kt | 155 ++++++++++++++++++ .../presentation/ui/enroll/EnrollScreen.kt | 13 +- 2 files changed, 159 insertions(+), 9 deletions(-) create mode 100644 app/src/main/java/org/sopt/teamdateroad/presentation/ui/component/bottomsheet/DateRoadDatePickerBottomSheet.kt diff --git a/app/src/main/java/org/sopt/teamdateroad/presentation/ui/component/bottomsheet/DateRoadDatePickerBottomSheet.kt b/app/src/main/java/org/sopt/teamdateroad/presentation/ui/component/bottomsheet/DateRoadDatePickerBottomSheet.kt new file mode 100644 index 0000000..a488d70 --- /dev/null +++ b/app/src/main/java/org/sopt/teamdateroad/presentation/ui/component/bottomsheet/DateRoadDatePickerBottomSheet.kt @@ -0,0 +1,155 @@ +package org.sopt.teamdateroad.presentation.ui.component.bottomsheet + +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.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.material3.Button +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import org.sopt.teamdateroad.presentation.ui.component.bottomsheet.model.Picker +import org.sopt.teamdateroad.presentation.ui.component.numberpicker.DateRoadNumberPicker +import org.sopt.teamdateroad.presentation.ui.component.numberpicker.state.PickerState +import org.sopt.teamdateroad.presentation.util.DatePicker +import org.sopt.teamdateroad.ui.theme.DateRoadTheme + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun DateRoadDatePickerBottomSheet( + isBottomSheetOpen: Boolean, + isButtonEnabled: Boolean, + buttonText: String, + onDatePickerBottomSheetButtonClick: (String) -> Unit, + onDismissRequest: () -> Unit = {} +) { + val yearItems = (DatePicker.YEAR_START..DatePicker.YEAR_END).map { it.toString() } + val monthItems = (DatePicker.MONTH_START..DatePicker.MONTH_END).map { it.toString().padStart(2, '0') } + + val yearState = remember { PickerState() } + val monthState = remember { PickerState() } + val dayState = remember { PickerState() } + val dayItemsState = remember { mutableStateOf((1..31).map { it.toString().padStart(2, '0') }) } + + LaunchedEffect(yearState.selectedItem, monthState.selectedItem) { + val year = yearState.selectedItem.toIntOrNull() ?: DatePicker.YEAR_START + val month = monthState.selectedItem.toIntOrNull() ?: DatePicker.MONTH_START + val lastDay = getLastDayOfMonth(year, month) + val newDays = (DatePicker.DAY_START..lastDay).map { it.toString().padStart(2, '0') } + + dayItemsState.value = newDays + if (dayState.selectedItem !in newDays) { + dayState.selectedItem = newDays.first() + } + } + + val yearPicker = Picker( + items = yearItems, + startIndex = yearItems.indexOf(yearState.selectedItem), + pickerState = yearState + ) + val monthPicker = Picker( + items = monthItems, + startIndex = monthItems.indexOf(monthState.selectedItem), + pickerState = monthState + ) + val dayPicker = Picker( + items = dayItemsState.value, + startIndex = dayItemsState.value.indexOf(dayState.selectedItem), + pickerState = dayState + ) + + val pickers = listOf(yearPicker, monthPicker, dayPicker) + + LaunchedEffect(Unit) { + yearState.selectedItem = yearItems[DatePicker.YEAR_START_INDEX] + monthState.selectedItem = monthItems.first() + dayState.selectedItem = dayItemsState.value.first() + } + + DateRoadBottomSheet( + modifier = Modifier.padding(top = 20.dp, bottom = 16.dp, start = 16.dp, end = 16.dp), + isBottomSheetOpen = isBottomSheetOpen, + isButtonEnabled = isButtonEnabled, + buttonText = buttonText, + onButtonClick = { + val selectedDate = pickers.joinToString(separator = DatePicker.SEPARATOR) { + it.pickerState.selectedItem.padStart(2, '0') + } + onDatePickerBottomSheetButtonClick(selectedDate) + // 상태 초기화 + yearState.selectedItem = yearItems[DatePicker.YEAR_START_INDEX] + monthState.selectedItem = monthItems.first() + dayState.selectedItem = dayItemsState.value.first() + }, + onDismissRequest = { + yearState.selectedItem = yearItems[DatePicker.YEAR_START_INDEX] + monthState.selectedItem = monthItems.first() + dayState.selectedItem = dayItemsState.value.first() + onDismissRequest() + } + ) { + Column { + Row(modifier = Modifier.fillMaxWidth()) { + pickers.forEachIndexed { index, item -> + DateRoadNumberPicker( + modifier = Modifier.weight(1f), + items = item.items, + startIndex = if (index == 0)item.items.indexOf(item.pickerState.selectedItem) else 0, + pickerState = item.pickerState + ) + if (index != pickers.size - 1) { + Spacer(modifier = Modifier.width(17.dp)) + } + } + } + Spacer(modifier = Modifier.height(19.dp)) + } + } +} + +fun getLastDayOfMonth(year: Int, month: Int): Int { + return when (month) { + 1, 3, 5, 7, 8, 10, 12 -> 31 + 4, 6, 9, 11 -> 30 + 2 -> if (isLeapYear(year)) 29 else 28 + else -> 31 + } +} + +fun isLeapYear(year: Int): Boolean { + return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0) +} + +@Preview +@Composable +fun DateRoadDatePickerBottomSheetPreview() { + var isBottomSheetOpen by rememberSaveable { mutableStateOf(false) } + + Button(onClick = { isBottomSheetOpen = true }) { + Text( + text = "DateRoadPickerBottomSheet", + color = DateRoadTheme.colors.black, + style = DateRoadTheme.typography.titleExtra24 + ) + } + + DateRoadDatePickerBottomSheet( + isBottomSheetOpen = isBottomSheetOpen, + isButtonEnabled = true, + buttonText = "취소", + onDatePickerBottomSheetButtonClick = {} + ) +} diff --git a/app/src/main/java/org/sopt/teamdateroad/presentation/ui/enroll/EnrollScreen.kt b/app/src/main/java/org/sopt/teamdateroad/presentation/ui/enroll/EnrollScreen.kt index a68a9d2..08294e8 100644 --- a/app/src/main/java/org/sopt/teamdateroad/presentation/ui/enroll/EnrollScreen.kt +++ b/app/src/main/java/org/sopt/teamdateroad/presentation/ui/enroll/EnrollScreen.kt @@ -44,6 +44,7 @@ import org.sopt.teamdateroad.presentation.type.EnrollType import org.sopt.teamdateroad.presentation.type.MyCourseType import org.sopt.teamdateroad.presentation.type.OneButtonDialogType import org.sopt.teamdateroad.presentation.type.OneButtonDialogWithDescriptionType +import org.sopt.teamdateroad.presentation.ui.component.bottomsheet.DateRoadDatePickerBottomSheet import org.sopt.teamdateroad.presentation.ui.component.bottomsheet.DateRoadPickerBottomSheet import org.sopt.teamdateroad.presentation.ui.component.bottomsheet.DateRoadRegionBottomSheet import org.sopt.teamdateroad.presentation.ui.component.button.DateRoadBasicButton @@ -56,7 +57,6 @@ import org.sopt.teamdateroad.presentation.ui.component.view.DateRoadErrorView import org.sopt.teamdateroad.presentation.ui.component.view.DateRoadLoadingView import org.sopt.teamdateroad.presentation.ui.enroll.component.EnrollPhotos import org.sopt.teamdateroad.presentation.util.DatePicker -import org.sopt.teamdateroad.presentation.util.DatePicker.SEPARATOR import org.sopt.teamdateroad.presentation.util.EnrollAmplitude.CLICK_BRING_COURSE import org.sopt.teamdateroad.presentation.util.EnrollAmplitude.CLICK_COURSE1_BACK import org.sopt.teamdateroad.presentation.util.EnrollAmplitude.CLICK_COURSE2_BACK @@ -501,17 +501,12 @@ fun EnrollScreen( Spacer(modifier = Modifier.height(16.dp)) } - DateRoadPickerBottomSheet( + DateRoadDatePickerBottomSheet( isBottomSheetOpen = enrollUiState.isDatePickerBottomSheetOpen, isButtonEnabled = true, buttonText = stringResource(id = R.string.apply), - onButtonClick = { - onDatePickerBottomSheetButtonClick( - enrollUiState.datePickers.joinToString(separator = SEPARATOR) { it.pickerState.selectedItem.padStart(2, '0') } - ) - }, - onDismissRequest = onDatePickerBottomSheetDismissRequest, - pickers = enrollUiState.datePickers + onDatePickerBottomSheetButtonClick = onDatePickerBottomSheetButtonClick, + onDismissRequest = onDatePickerBottomSheetDismissRequest ) DateRoadPickerBottomSheet( From fd6076f650fdad1e936f97edd22485a97144ea13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=B5=E1=86=B7=E1=84=8C=E1=85=B5=E1=86=AB?= =?UTF-8?q?=E1=84=8B=E1=85=AE?= Date: Wed, 7 May 2025 23:38:33 +0900 Subject: [PATCH 2/3] =?UTF-8?q?feat:=20=EC=B9=B4=ED=86=A1=20=EB=B2=84?= =?UTF-8?q?=ED=8A=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/component/button/DateRoadKakaoLoginButton.kt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/org/sopt/teamdateroad/presentation/ui/component/button/DateRoadKakaoLoginButton.kt b/app/src/main/java/org/sopt/teamdateroad/presentation/ui/component/button/DateRoadKakaoLoginButton.kt index 150f2f0..fbe238e 100644 --- a/app/src/main/java/org/sopt/teamdateroad/presentation/ui/component/button/DateRoadKakaoLoginButton.kt +++ b/app/src/main/java/org/sopt/teamdateroad/presentation/ui/component/button/DateRoadKakaoLoginButton.kt @@ -1,6 +1,7 @@ package org.sopt.teamdateroad.presentation.ui.component.button import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth @@ -39,16 +40,16 @@ fun DateRoadKakaoLoginButton( paddingHorizontal = 14.dp, onClick = onClick ) { - Row( - verticalAlignment = Alignment.CenterVertically + Box( + modifier.fillMaxWidth() ) { Image( painter = painterResource(id = R.drawable.ic_kakao_logo), contentDescription = null, modifier = Modifier .clip(CircleShape) + .align(Alignment.CenterStart) ) - Spacer(modifier = Modifier.size(5.dp)) Text( text = stringResource(id = R.string.kakao_login), fontSize = 15.sp, @@ -57,7 +58,7 @@ fun DateRoadKakaoLoginButton( color = contentColor, textAlign = TextAlign.Center, modifier = Modifier - .align(Alignment.CenterVertically) + .align(Alignment.Center) .fillMaxWidth() ) } From 2619f6406e0c36971b4892b7071a53e504e20f3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=B5=E1=86=B7=E1=84=8C=E1=85=B5=E1=86=AB?= =?UTF-8?q?=E1=84=8B=E1=85=AE?= Date: Thu, 8 May 2025 00:23:26 +0900 Subject: [PATCH 3/3] =?UTF-8?q?feat:=20=ED=83=9C=EA=B7=B8=20=EC=9C=84?= =?UTF-8?q?=EC=B9=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../button/DateRoadKakaoLoginButton.kt | 5 +---- .../ui/component/tag/DateRoadTag.kt | 4 +++- .../ui/component/tag/DateRoadTextTag.kt | 19 ++++++------------- 3 files changed, 10 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/org/sopt/teamdateroad/presentation/ui/component/button/DateRoadKakaoLoginButton.kt b/app/src/main/java/org/sopt/teamdateroad/presentation/ui/component/button/DateRoadKakaoLoginButton.kt index fbe238e..57a31ac 100644 --- a/app/src/main/java/org/sopt/teamdateroad/presentation/ui/component/button/DateRoadKakaoLoginButton.kt +++ b/app/src/main/java/org/sopt/teamdateroad/presentation/ui/component/button/DateRoadKakaoLoginButton.kt @@ -2,10 +2,7 @@ package org.sopt.teamdateroad.presentation.ui.component.button import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -41,7 +38,7 @@ fun DateRoadKakaoLoginButton( onClick = onClick ) { Box( - modifier.fillMaxWidth() + modifier.fillMaxWidth() ) { Image( painter = painterResource(id = R.drawable.ic_kakao_logo), diff --git a/app/src/main/java/org/sopt/teamdateroad/presentation/ui/component/tag/DateRoadTag.kt b/app/src/main/java/org/sopt/teamdateroad/presentation/ui/component/tag/DateRoadTag.kt index a132a21..546f6b4 100644 --- a/app/src/main/java/org/sopt/teamdateroad/presentation/ui/component/tag/DateRoadTag.kt +++ b/app/src/main/java/org/sopt/teamdateroad/presentation/ui/component/tag/DateRoadTag.kt @@ -5,6 +5,7 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.RoundedCornerShape 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.unit.dp @@ -20,7 +21,8 @@ fun DateRoadTag( modifier = modifier .clip(RoundedCornerShape(tagType.roundedCornerShape.dp)) .background(color = tagType.backgroundColor) - .padding(horizontal = tagType.paddingHorizontal.dp, vertical = tagType.paddingVertical.dp) + .padding(horizontal = tagType.paddingHorizontal.dp, vertical = tagType.paddingVertical.dp), + contentAlignment = Alignment.Center ) { content() } diff --git a/app/src/main/java/org/sopt/teamdateroad/presentation/ui/component/tag/DateRoadTextTag.kt b/app/src/main/java/org/sopt/teamdateroad/presentation/ui/component/tag/DateRoadTextTag.kt index f504c49..aa15e5c 100644 --- a/app/src/main/java/org/sopt/teamdateroad/presentation/ui/component/tag/DateRoadTextTag.kt +++ b/app/src/main/java/org/sopt/teamdateroad/presentation/ui/component/tag/DateRoadTextTag.kt @@ -1,10 +1,8 @@ package org.sopt.teamdateroad.presentation.ui.component.tag -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview @@ -21,17 +19,12 @@ fun DateRoadTextTag( modifier = modifier, tagType = tagContentType ) { - Box( - modifier = modifier, - contentAlignment = Alignment.Center - ) { - Text( - text = textContent, - style = tagContentType.textStyle, - color = tagContentType.contentColor, - textAlign = TextAlign.Center - ) - } + Text( + text = textContent, + style = tagContentType.textStyle, + color = tagContentType.contentColor, + textAlign = TextAlign.Center + ) } }