-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Feature] 캘린더 컴포넌트를 구현합니다. #19
Changes from 9 commits
e6dec42
e3f3bf9
bdd7396
b249a2b
933abfb
0060f8b
4e212df
ef6e823
b9f976a
544b353
790f85f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,44 @@ import java.time.format.DateTimeFormatter | |
import java.util.Locale | ||
|
||
class CalendarTest : BehaviorSpec({ | ||
Given("현재 날짜가 포함된 달의 모든 날을 가져올 수 있다.") { | ||
var date: LocalDate | ||
var calendar: Calendar | ||
var actual: List<StudyDay> | ||
|
||
When("2024년 1월 5일이 주어지면") { | ||
date = LocalDate.of(2024, 1, 5) | ||
calendar = Calendar(date) | ||
|
||
Then("31개의 날들이 반환된다") { | ||
actual = calendar.getMonth() | ||
actual.size shouldBe 31 | ||
} | ||
|
||
Then("순서를 유지한체 1일부터 31일 까지 반환된다") { | ||
actual = calendar.getMonth() | ||
actual.first().date shouldBe LocalDate.of(2024, 1, 1) | ||
actual.last().date shouldBe LocalDate.of(2024, 1, 31) | ||
} | ||
} | ||
|
||
When("2024년 2월 15일이 주어지면") { | ||
date = LocalDate.of(2024, 2, 15) | ||
calendar = Calendar(date) | ||
|
||
Then("29개의 날들이 반환된다") { | ||
actual = calendar.getMonth() | ||
actual.size shouldBe 29 | ||
} | ||
|
||
Then("윤년이기 때문에 1부터 29일까지 반환된다.") { | ||
actual = calendar.getMonth() | ||
actual.first().date shouldBe LocalDate.of(2024, 2, 1) | ||
actual.last().date shouldBe LocalDate.of(2024, 2, 29) | ||
} | ||
Comment on lines
+40
to
+44
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 윤년처리까지 치밀하게 테스트 해보셨군요..! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 워낙에 애초에 잘 짜여진 Java의 라이브러리다 보니 엣지케이스 위주로 테스트를 진행하였습니다! |
||
} | ||
} | ||
|
||
Given("LocalDate가 주어지면, 해당 달의 끝날짜를 알 수 있다.") { | ||
var date: LocalDate | ||
var calendar: Calendar | ||
|
@@ -178,8 +216,14 @@ class CalendarTest : BehaviorSpec({ | |
actual shouldBe | ||
listOf( | ||
StudyDay(LocalDate.of(2024, 2, 1), StudyRoomUsage.USED_ONCE), | ||
StudyDay(LocalDate.of(2024, 2, 3), StudyRoomUsage.USED_ONCE_EXTENDED_ONCE), | ||
StudyDay(LocalDate.of(2024, 2, 4), StudyRoomUsage.USED_ONCE_EXTENDED_ONCE), | ||
StudyDay( | ||
LocalDate.of(2024, 2, 3), | ||
StudyRoomUsage.USED_ONCE_EXTENDED_ONCE, | ||
), | ||
StudyDay( | ||
LocalDate.of(2024, 2, 4), | ||
StudyRoomUsage.USED_ONCE_EXTENDED_ONCE, | ||
), | ||
) | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
/build |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
plugins { | ||
id("hongikyeolgong2.android.feature") | ||
} | ||
|
||
android { | ||
namespace = "com.teamhy2.hongikyeolgong2.calendar.presentation" | ||
} | ||
|
||
dependencies { | ||
implementation(projects.calendarDomain) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Add project specific ProGuard rules here. | ||
# You can control the set of applied configuration files using the | ||
# proguardFiles setting in build.gradle. | ||
# | ||
# For more details, see | ||
# http://developer.android.com/guide/developing/tools/proguard.html | ||
|
||
# If your project uses WebView with JS, uncomment the following | ||
# and specify the fully qualified class name to the JavaScript interface | ||
# class: | ||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview { | ||
# public *; | ||
#} | ||
|
||
# Uncomment this to preserve the line number information for | ||
# debugging stack traces. | ||
#-keepattributes SourceFile,LineNumberTable | ||
|
||
# If you keep the line number information, uncomment this to | ||
# hide the original source file name. | ||
#-renamesourcefileattribute SourceFile |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package com.hongikyeolgong2.calendar.presentation | ||
|
||
import androidx.test.ext.junit.runners.AndroidJUnit4 | ||
import androidx.test.platform.app.InstrumentationRegistry | ||
import junit.framework.TestCase.assertEquals | ||
import org.junit.Test | ||
import org.junit.runner.RunWith | ||
|
||
/** | ||
* Instrumented test, which will execute on an Android device. | ||
* | ||
* See [testing documentation](http://d.android.com/tools/testing). | ||
*/ | ||
@RunWith(AndroidJUnit4::class) | ||
class ExampleInstrumentedTest { | ||
@Test | ||
fun useAppContext() { | ||
// Context of the app under test. | ||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext | ||
assertEquals("com.hongikyeolgong2.calendar.presentation.test", appContext.packageName) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<manifest /> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,210 @@ | ||
package com.hongikyeolgong2.calendar.presentation | ||
|
||
import androidx.compose.foundation.clickable | ||
import androidx.compose.foundation.interaction.MutableInteractionSource | ||
import androidx.compose.foundation.layout.Arrangement | ||
import androidx.compose.foundation.layout.Box | ||
import androidx.compose.foundation.layout.Column | ||
import androidx.compose.foundation.layout.Row | ||
import androidx.compose.foundation.layout.Spacer | ||
import androidx.compose.foundation.layout.height | ||
import androidx.compose.foundation.layout.padding | ||
import androidx.compose.foundation.lazy.grid.GridCells | ||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid | ||
import androidx.compose.foundation.lazy.grid.items | ||
import androidx.compose.material3.Icon | ||
import androidx.compose.material3.Text | ||
import androidx.compose.runtime.Composable | ||
import androidx.compose.runtime.getValue | ||
import androidx.compose.runtime.mutableStateOf | ||
import androidx.compose.runtime.remember | ||
import androidx.compose.runtime.setValue | ||
import androidx.compose.ui.Alignment | ||
import androidx.compose.ui.Modifier | ||
import androidx.compose.ui.res.painterResource | ||
import androidx.compose.ui.res.stringResource | ||
import androidx.compose.ui.text.style.TextAlign | ||
import androidx.compose.ui.tooling.preview.Preview | ||
import androidx.compose.ui.unit.dp | ||
import com.hongikyeolgong2.calendar.model.Calendar | ||
import com.hongikyeolgong2.calendar.model.StudyDay | ||
import com.hongikyeolgong2.calendar.model.StudyRoomUsage | ||
import com.teamhy2.designsystem.R | ||
import com.teamhy2.designsystem.ui.theme.Gray100 | ||
import com.teamhy2.designsystem.ui.theme.Gray300 | ||
import com.teamhy2.designsystem.ui.theme.HY2Theme | ||
import com.teamhy2.designsystem.ui.theme.HY2Typography | ||
import com.teamhy2.hongikyeolgong2.calendar.presentation.R.string.description_next_month | ||
import com.teamhy2.hongikyeolgong2.calendar.presentation.R.string.description_previous_month | ||
import java.time.LocalDate | ||
|
||
private const val DAY_DEFAULT_MARGIN = 5 | ||
|
||
@Composable | ||
fun Hy2Calendar( | ||
title: String, | ||
days: List<StudyDay>, | ||
onPreviousMonthClick: () -> Unit, | ||
onNextMonthClick: () -> Unit, | ||
modifier: Modifier = Modifier, | ||
) { | ||
Column(modifier = modifier) { | ||
CalendarHeader( | ||
title = title, | ||
onPreviousMonthClick = onPreviousMonthClick, | ||
onNextMonthClick = onNextMonthClick, | ||
) | ||
Spacer(modifier = Modifier.height(12.dp)) | ||
Row(modifier = Modifier.padding(bottom = 8.dp)) { | ||
DayOfWeek.entries.forEach { dayOfWeek -> | ||
DayOfWeek( | ||
name = dayOfWeek.abbreviation, | ||
modifier = Modifier.weight(1f), | ||
) | ||
} | ||
} | ||
LazyVerticalGrid( | ||
columns = GridCells.Fixed(7), | ||
verticalArrangement = Arrangement.spacedBy(DAY_DEFAULT_MARGIN.dp), | ||
horizontalArrangement = Arrangement.spacedBy(DAY_DEFAULT_MARGIN.dp), | ||
) { | ||
items((days.first().date.dayOfWeek.ordinal + 1) % 7) { | ||
Box(modifier = Modifier.weight(1f)) | ||
} | ||
|
||
items(days) { | ||
Day(studyDay = it, modifier = Modifier.weight(1f)) | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 월을 표시하는 로직과 일을 표시하는 로직을 분리하면 가독성이더 좋아지지 않을까 제안드려봅니다! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 반영완료 하였습니다. 가독성을 위한 분리를 해보고 추후 장단점을 피부로 같이 느껴보는 시간을 가졌음 좋겠습니다! |
||
} | ||
} | ||
|
||
@Composable | ||
fun CalendarHeader( | ||
title: String, | ||
onPreviousMonthClick: () -> Unit, | ||
onNextMonthClick: () -> Unit, | ||
modifier: Modifier = Modifier, | ||
) { | ||
Row( | ||
modifier = modifier, | ||
verticalAlignment = Alignment.CenterVertically, | ||
) { | ||
Text( | ||
text = title, | ||
style = HY2Typography().title01, | ||
color = Gray100, | ||
) | ||
Spacer(modifier = Modifier.weight(1f)) | ||
Icon( | ||
painter = painterResource(id = R.drawable.ic_arrow_left), | ||
modifier = | ||
Modifier.clickable( | ||
interactionSource = MutableInteractionSource(), | ||
indication = null, | ||
onClick = onPreviousMonthClick, | ||
), | ||
tint = Gray300, | ||
contentDescription = stringResource(description_previous_month), | ||
) | ||
Icon( | ||
painter = painterResource(id = R.drawable.ic_arrow_right), | ||
modifier = | ||
Modifier.clickable( | ||
interactionSource = MutableInteractionSource(), | ||
indication = null, | ||
onClick = onNextMonthClick, | ||
), | ||
tint = Gray300, | ||
contentDescription = stringResource(description_next_month), | ||
) | ||
} | ||
} | ||
|
||
@Composable | ||
fun DayOfWeek( | ||
name: String, | ||
modifier: Modifier = Modifier, | ||
) { | ||
Text( | ||
text = name, | ||
modifier = modifier, | ||
textAlign = TextAlign.Center, | ||
style = HY2Typography().body04, | ||
color = Gray300, | ||
) | ||
} | ||
|
||
@Preview | ||
@Composable | ||
private fun Hy2CalendarPreview() { | ||
HY2Theme { | ||
val calendar by remember { | ||
mutableStateOf( | ||
Calendar( | ||
studyDays = | ||
listOf( | ||
StudyDay( | ||
date = LocalDate.now().withDayOfMonth(2), | ||
studyRoomUsage = StudyRoomUsage.USED_ONCE_EXTENDED_ONCE, | ||
), | ||
StudyDay( | ||
date = LocalDate.now().withDayOfMonth(5), | ||
studyRoomUsage = StudyRoomUsage.USED_ONCE, | ||
), | ||
StudyDay( | ||
date = LocalDate.now().withDayOfMonth(10), | ||
studyRoomUsage = StudyRoomUsage.USED_ONCE_EXTENDED_TWICE, | ||
), | ||
StudyDay( | ||
date = LocalDate.now().withDayOfMonth(20), | ||
studyRoomUsage = StudyRoomUsage.NEVER_USED, | ||
), | ||
), | ||
), | ||
) | ||
} | ||
var title by remember { | ||
mutableStateOf(calendar.now) | ||
} | ||
|
||
var month by remember { | ||
mutableStateOf(calendar.getMonth()) | ||
} | ||
|
||
Hy2Calendar( | ||
title = title, | ||
days = month, | ||
onPreviousMonthClick = { | ||
calendar.moveToPreviousMonth() | ||
title = calendar.now | ||
month = calendar.getMonth() | ||
}, | ||
onNextMonthClick = { | ||
calendar.moveToNextMonth() | ||
title = calendar.now | ||
month = calendar.getMonth() | ||
}, | ||
) | ||
} | ||
} | ||
|
||
@Preview | ||
@Composable | ||
private fun CalendarHeaderPreview() { | ||
HY2Theme { | ||
CalendarHeader( | ||
title = "Jan 2024", | ||
onPreviousMonthClick = { }, | ||
onNextMonthClick = { }, | ||
) | ||
} | ||
} | ||
|
||
@Preview | ||
@Composable | ||
private fun DayOfWeekPreview() { | ||
HY2Theme { | ||
DayOfWeek(name = "Mon") | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Locale.ENGLISH 를 적용하신 이유가 무엇인가요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
명시해주지 않으면 의도와는 다르게 디폴트로 들어가는 인자가
1월 2024
이런식으로 디바이스의 언어설정 기준으로 들어가게 됩니다.디자인상으로 의도된건
Jan 2024
와 같은 영어약어의 표현이기 때문에 해당 Locale 설정을 추가하였습니다.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
오 디바이스 언어를 인식하는줄은 몰랐습니다! 새로운 사실을 배워가네요