From fad4f2ec307860d0fbd93e32a7dbb59c9e3766e9 Mon Sep 17 00:00:00 2001 From: sunghyun Date: Mon, 2 Jun 2025 09:41:20 +0900 Subject: [PATCH 1/6] =?UTF-8?q?:lipstick:=20MS=20Header=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../designsystem/component/MSHeader.kt | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 core/designsystem/src/main/java/com/idiotfrogs/designsystem/component/MSHeader.kt diff --git a/core/designsystem/src/main/java/com/idiotfrogs/designsystem/component/MSHeader.kt b/core/designsystem/src/main/java/com/idiotfrogs/designsystem/component/MSHeader.kt new file mode 100644 index 0000000..2119019 --- /dev/null +++ b/core/designsystem/src/main/java/com/idiotfrogs/designsystem/component/MSHeader.kt @@ -0,0 +1,71 @@ +package com.idiotfrogs.designsystem.component + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +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.size +import androidx.compose.material3.Icon +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.idiotfrogs.designsystem.util.noRippleClickable +import com.idiotfrogs.resource.R + +@Composable +fun MSDetailHeader( + navigateToBack: () -> Unit, + modifier: Modifier = Modifier, + title: String = "", + paddingValues: PaddingValues = PaddingValues(horizontal = 20.dp, vertical = 16.dp), + trailingContent: @Composable (() -> Unit)? = null, +) { + Box( + modifier = modifier + .fillMaxWidth() + .padding(paddingValues), + ) { + Icon( + modifier = Modifier + .size(24.dp) + .align(Alignment.CenterStart) + .noRippleClickable { navigateToBack() }, + painter = painterResource(R.drawable.ic_chevron_left), + contentDescription = "Back" + ) + MSText( + modifier = Modifier.align(Alignment.Center), + text = title + ) + trailingContent?.let { + Box(Modifier.align(Alignment.CenterEnd)) { it() } + } + } +} + +@Preview +@Composable +fun MSDetailHeaderPreview() { + Column { + MSDetailHeader( + title = "타임 티켓 생성하기", + navigateToBack = {} + ) + Spacer(Modifier.height(30.dp)) + MSDetailHeader( + title = "맴버 추가", + navigateToBack = {} + ) { + Icon( + painter = painterResource(R.drawable.ic_plus), + contentDescription = "Back" + ) + } + } +} \ No newline at end of file From d615e0938ca30d875e77c8c8c457d043a4358db0 Mon Sep 17 00:00:00 2001 From: sunghyun Date: Mon, 2 Jun 2025 09:42:06 +0900 Subject: [PATCH 2/6] =?UTF-8?q?:truck:=20drawable=20=EB=A6=AC=EC=86=8C?= =?UTF-8?q?=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/res/drawable/ic_calender_after.xml | 10 ++++++++++ .../src/main/res/drawable/ic_calender_before.xml | 10 ++++++++++ common/resource/src/main/res/drawable/ic_photo.xml | 10 ++++++++++ 3 files changed, 30 insertions(+) create mode 100644 common/resource/src/main/res/drawable/ic_calender_after.xml create mode 100644 common/resource/src/main/res/drawable/ic_calender_before.xml create mode 100644 common/resource/src/main/res/drawable/ic_photo.xml diff --git a/common/resource/src/main/res/drawable/ic_calender_after.xml b/common/resource/src/main/res/drawable/ic_calender_after.xml new file mode 100644 index 0000000..705abbf --- /dev/null +++ b/common/resource/src/main/res/drawable/ic_calender_after.xml @@ -0,0 +1,10 @@ + + + diff --git a/common/resource/src/main/res/drawable/ic_calender_before.xml b/common/resource/src/main/res/drawable/ic_calender_before.xml new file mode 100644 index 0000000..d2ac275 --- /dev/null +++ b/common/resource/src/main/res/drawable/ic_calender_before.xml @@ -0,0 +1,10 @@ + + + diff --git a/common/resource/src/main/res/drawable/ic_photo.xml b/common/resource/src/main/res/drawable/ic_photo.xml new file mode 100644 index 0000000..ca2cfe6 --- /dev/null +++ b/common/resource/src/main/res/drawable/ic_photo.xml @@ -0,0 +1,10 @@ + + + From 95eb51e3f281a883421e004db27710fd729af65a Mon Sep 17 00:00:00 2001 From: sunghyun Date: Mon, 2 Jun 2025 09:42:41 +0900 Subject: [PATCH 3/6] =?UTF-8?q?:arrow=5Fup:=20minSdk=2024=20->=2026=20?= =?UTF-8?q?=EC=98=AC=EB=A6=AC=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/kotlin/com/idiotfrogs/memoryseal/KotlinAndroid.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-logic/src/main/kotlin/com/idiotfrogs/memoryseal/KotlinAndroid.kt b/build-logic/src/main/kotlin/com/idiotfrogs/memoryseal/KotlinAndroid.kt index 8ce4602..0122210 100644 --- a/build-logic/src/main/kotlin/com/idiotfrogs/memoryseal/KotlinAndroid.kt +++ b/build-logic/src/main/kotlin/com/idiotfrogs/memoryseal/KotlinAndroid.kt @@ -12,7 +12,7 @@ internal fun Project.configureKotlinAndroid(commonExtension: CommonExtension<*, compileSdk = 35 defaultConfig { - minSdk = 24 + minSdk = 26 testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } From 90a373ca6c15d01fb706ef62942f3bfc88537625 Mon Sep 17 00:00:00 2001 From: sunghyun Date: Mon, 2 Jun 2025 09:42:54 +0900 Subject: [PATCH 4/6] =?UTF-8?q?:lipstick:=20MSCalender=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../designsystem/component/MSCalender.kt | 193 ++++++++++++++++++ 1 file changed, 193 insertions(+) create mode 100644 core/designsystem/src/main/java/com/idiotfrogs/designsystem/component/MSCalender.kt diff --git a/core/designsystem/src/main/java/com/idiotfrogs/designsystem/component/MSCalender.kt b/core/designsystem/src/main/java/com/idiotfrogs/designsystem/component/MSCalender.kt new file mode 100644 index 0000000..e0ac7b1 --- /dev/null +++ b/core/designsystem/src/main/java/com/idiotfrogs/designsystem/component/MSCalender.kt @@ -0,0 +1,193 @@ +package com.idiotfrogs.designsystem.component + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +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.aspectRatio +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.foundation.lazy.grid.items +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Icon +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.idiotfrogs.designsystem.theme.MSTheme +import com.idiotfrogs.designsystem.util.noRippleClickable +import com.idiotfrogs.resource.R +import java.time.LocalDate +import java.time.YearMonth +import kotlin.math.ceil + +@Composable +fun MSCalender( + onDateSelected: (LocalDate) -> Unit +) { + val selectedDate = remember { mutableStateOf(LocalDate.now()) } + var currentYearMonth by remember { mutableStateOf(YearMonth.now()) } + + val today = LocalDate.now() + val currentMonth = YearMonth.from(today) + val canGoToPrevMonth = currentYearMonth > currentMonth + + val daysOfWeek = listOf("일", "월", "화", "수", "목", "금", "토") + + val firstDayOfMonth = currentYearMonth.atDay(1) + val firstDayOfWeek = firstDayOfMonth.dayOfWeek.value % 7 // 일요일 = 0 + + val prevMonth = currentYearMonth.minusMonths(1) + val prevMonthLength = prevMonth.lengthOfMonth() + val leadingDates = (0 until firstDayOfWeek).map { + prevMonth.atDay(prevMonthLength - firstDayOfWeek + it + 1) + } + + val currentMonthDates = (1..currentYearMonth.lengthOfMonth()).map { + currentYearMonth.atDay(it) + } + + val totalCells = leadingDates.size + currentMonthDates.size + val rowCount = ceil(totalCells / 7.0).toInt() + + val trailingCount = rowCount * 7 - totalCells + val nextMonth = currentYearMonth.plusMonths(1) + val trailingDates = (1..trailingCount).map { nextMonth.atDay(it) } + + val dates = leadingDates + currentMonthDates + trailingDates + + Column( + modifier = Modifier + .border(1.dp, MSTheme.color.greyG2, RoundedCornerShape(12.dp)) + .padding(12.dp) + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.fillMaxWidth() + ) { + MSText( + text = "${currentYearMonth.year}년 ${currentYearMonth.monthValue}월", + fontSize = 14.dp, + color = MSTheme.color.greyG5 + ) + Spacer(Modifier.weight(1f)) + Icon( + modifier = Modifier.noRippleClickable { + if (canGoToPrevMonth) currentYearMonth = currentYearMonth.minusMonths(1) + }, + painter = painterResource(R.drawable.ic_calender_before), + contentDescription = "이전 달", + tint = if (canGoToPrevMonth) Color.Unspecified else MSTheme.color.greyG2 + ) + Spacer(Modifier.width(8.dp)) + Icon( + modifier = Modifier.noRippleClickable { + currentYearMonth = currentYearMonth.plusMonths(1) + }, + painter = painterResource(R.drawable.ic_calender_after), + contentDescription = "다음 달" + ) + } + + Spacer(modifier = Modifier.height(12.dp)) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween + ) { + for (day in daysOfWeek) { + MSText( + text = day, + modifier = Modifier.weight(1f), + textAlign = TextAlign.Center, + fontWeight = FontWeight.Medium, + color = MSTheme.color.greyG4, + fontSize = 12.dp + ) + } + } + + Spacer(modifier = Modifier.height(8.dp)) + + LazyVerticalGrid( + columns = GridCells.Fixed(7), + userScrollEnabled = false, + modifier = Modifier + .fillMaxWidth() + .height((rowCount * 50).dp) + ) { + items(dates) { date -> + val isCurrentMonth = date.month == currentYearMonth.month + val isSelected = date == selectedDate.value + val isPast = date.isBefore(today) + + Box( + modifier = Modifier + .aspectRatio(1f) + .clip(RoundedCornerShape(8.dp)) + .background( + when { + isSelected -> MSTheme.color.primaryNormal + else -> Color.Transparent + } + ) + .noRippleClickable { + if (!isPast) { + selectedDate.value = date + + val selectedMonth = YearMonth.from(date) + if (selectedMonth != currentYearMonth) { + currentYearMonth = selectedMonth + } + + onDateSelected(date) + } + }, + contentAlignment = Alignment.Center + ) { + MSText( + text = date.dayOfMonth.toString(), + color = when { + isSelected -> MSTheme.color.white + isCurrentMonth -> MSTheme.color.greyG5 + else -> MSTheme.color.greyG2 + } + ) + } + } + } + } +} + + +@Preview +@Composable +private fun MsCalenderPreview() { + Column( + modifier = Modifier + .fillMaxSize() + .padding(horizontal = 20.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + MSCalender {} + } +} \ No newline at end of file From 53602de414988d106997bbeff82320ff93626b3b Mon Sep 17 00:00:00 2001 From: sunghyun Date: Mon, 2 Jun 2025 09:43:11 +0900 Subject: [PATCH 5/6] =?UTF-8?q?:lipstick:=20CreateScreen=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/idiotfrogs/create/CreateScreen.kt | 151 ++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 feature/create/src/main/java/com/idiotfrogs/create/CreateScreen.kt diff --git a/feature/create/src/main/java/com/idiotfrogs/create/CreateScreen.kt b/feature/create/src/main/java/com/idiotfrogs/create/CreateScreen.kt new file mode 100644 index 0000000..bbe3d9d --- /dev/null +++ b/feature/create/src/main/java/com/idiotfrogs/create/CreateScreen.kt @@ -0,0 +1,151 @@ +package com.idiotfrogs.create + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +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.imePadding +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.systemBarsPadding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.input.rememberTextFieldState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.ButtonDefaults +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.idiotfrogs.designsystem.component.MSButton +import com.idiotfrogs.designsystem.component.MSCalender +import com.idiotfrogs.designsystem.component.MSText +import com.idiotfrogs.designsystem.component.MSTextField +import com.idiotfrogs.designsystem.component.MSDetailHeader +import com.idiotfrogs.designsystem.theme.MSTheme +import com.idiotfrogs.designsystem.util.keyboardAutoScroll +import com.idiotfrogs.designsystem.util.noRippleClickable +import com.idiotfrogs.designsystem.util.rememberPickerState +import com.idiotfrogs.resource.R +import com.skydoves.landscapist.glide.GlideImage + +@Composable +fun CreateScreen(modifier: Modifier = Modifier) { + val titleTextFieldState = rememberTextFieldState() + val contentTextFieldState = rememberTextFieldState() + val scrollState = rememberScrollState() + val (imageUri, launchImagePicker) = rememberPickerState() + val enabled = titleTextFieldState.text.isNotEmpty() && contentTextFieldState.text.isNotEmpty() + + Column( + modifier = modifier + .fillMaxSize() + .background(MSTheme.color.white) + .systemBarsPadding() + .imePadding() + .padding(horizontal = 20.dp) + .keyboardAutoScroll(scrollState) + ) { + MSDetailHeader( + title = "타임 티켓 생성하기", + paddingValues = PaddingValues(vertical = 16.dp), + navigateToBack = {} + ) + Spacer(Modifier.height(24.dp)) + Column( + modifier = Modifier + .verticalScroll(state = scrollState) + .weight(1f), + ) { + MSText( + text = "사진", + fontSize = 12.dp, + fontWeight = FontWeight.Medium, + color = MSTheme.color.greyG5 + ) + Spacer(Modifier.height(8.dp)) + imageUri?.let { + GlideImage( + imageModel = { imageUri }, + modifier = Modifier + .noRippleClickable { launchImagePicker() } + .size(120.dp) + .clip(RoundedCornerShape(12.dp)) + ) + } ?: Image( + modifier = Modifier + .border(1.dp, MSTheme.color.greyG2, RoundedCornerShape(12.dp)) + .padding(48.dp) + .noRippleClickable { launchImagePicker() }, + painter = painterResource(R.drawable.ic_photo), + contentDescription = "사진" + ) + Spacer(Modifier.height(16.dp)) + MSText( + text = "제목", + fontSize = 12.dp, + fontWeight = FontWeight.Medium, + color = MSTheme.color.greyG5 + ) + Spacer(Modifier.height(8.dp)) + MSTextField( + modifier = Modifier.fillMaxWidth(), + textFieldState = titleTextFieldState, + hint = "제목을 입력해주세요." + ) + Spacer(Modifier.height(16.dp)) + MSText( + text = "간단한 설명", + fontSize = 12.dp, + fontWeight = FontWeight.Medium, + color = MSTheme.color.greyG5 + ) + Spacer(Modifier.height(8.dp)) + MSTextField( + modifier = Modifier.fillMaxWidth(), + textFieldState = contentTextFieldState, + hint = "설명을 입력해주세요." + ) + Spacer(Modifier.height(16.dp)) + MSText( + text = "오픈 날짜", + fontSize = 12.dp, + fontWeight = FontWeight.Medium, + color = MSTheme.color.greyG5 + ) + Spacer(Modifier.height(8.dp)) + MSCalender { } + Spacer(Modifier.height(24.dp)) + } + MSButton( + modifier = Modifier.fillMaxWidth(), + enabled = enabled, + colors = ButtonDefaults.buttonColors( + containerColor = MSTheme.color.primaryNormal, + disabledContainerColor = MSTheme.color.primaryLight + ), + onClick = {} + ) { + MSText( + text = "오픈 날짜", + fontSize = 12.dp, + fontWeight = FontWeight.Medium, + color = if (enabled) MSTheme.color.white else MSTheme.color.greyG3 + ) + } + } +} + +@Preview +@Composable +fun CreateScreenPreview() { + CreateScreen() +} \ No newline at end of file From 2034f1b165f06a237c0bd43168a85fc64c2fbfe5 Mon Sep 17 00:00:00 2001 From: sunghyun Date: Mon, 2 Jun 2025 09:43:42 +0900 Subject: [PATCH 6/6] =?UTF-8?q?:sparkles:=20NavHost=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 1 + app/src/main/java/com/idiotfrogs/memoryseal/MainActivity.kt | 4 ++++ .../src/main/java/com/idiotfrogs/navigation/Routes.kt | 2 ++ 3 files changed, 7 insertions(+) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index f64029e..507d346 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -7,6 +7,7 @@ plugins { dependencies { implementation(project(":feature:auth")) + implementation(project(":feature:create")) implementation(project(":core:designsystem")) implementation(project(":core:data")) implementation(project(":core:navigation")) diff --git a/app/src/main/java/com/idiotfrogs/memoryseal/MainActivity.kt b/app/src/main/java/com/idiotfrogs/memoryseal/MainActivity.kt index 5e3846f..2b1244a 100644 --- a/app/src/main/java/com/idiotfrogs/memoryseal/MainActivity.kt +++ b/app/src/main/java/com/idiotfrogs/memoryseal/MainActivity.kt @@ -17,6 +17,7 @@ import androidx.navigation.compose.rememberNavController import com.idiotfrogs.auth.login.LoginRoute import com.idiotfrogs.auth.signup.SignUpRoute import com.idiotfrogs.auth.util.LocalLoginManager +import com.idiotfrogs.create.CreateScreen import com.idiotfrogs.data.LoginManager import com.idiotfrogs.designsystem.theme.MSTheme import com.idiotfrogs.navigation.Routes @@ -58,6 +59,9 @@ class MainActivity : ComponentActivity() { navigateToMainScreen = {} ) } + composable { + CreateScreen() + } } } } diff --git a/core/navigation/src/main/java/com/idiotfrogs/navigation/Routes.kt b/core/navigation/src/main/java/com/idiotfrogs/navigation/Routes.kt index 6ce2472..b52d410 100644 --- a/core/navigation/src/main/java/com/idiotfrogs/navigation/Routes.kt +++ b/core/navigation/src/main/java/com/idiotfrogs/navigation/Routes.kt @@ -7,4 +7,6 @@ sealed interface Routes { data object Login : Routes @Serializable data object SignUp : Routes + @Serializable + data object Create : Routes }