Skip to content
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/#9] : 약속 생성 UI 구현 #12

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.sopt.core.designsystem.component.button

import androidx.compose.ui.graphics.Color
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.material3.Button
import androidx.compose.ui.unit.dp
import com.sopt.core.designsystem.theme.NoostakTheme

@Composable
fun NoostakButton(
text: String,
textColor: Color,
buttonColor: Color,
onButtonClick: () -> Unit,
modifier: Modifier = Modifier,
isEnabled: Boolean = true
twogarlic marked this conversation as resolved.
Show resolved Hide resolved
) {
Button(
modifier = modifier,
twogarlic marked this conversation as resolved.
Show resolved Hide resolved
shape = RoundedCornerShape(8.dp),
colors = ButtonDefaults.buttonColors(
containerColor = buttonColor,
disabledContainerColor = buttonColor.copy(alpha = 0.5f) // 비활성화 상태 색상
),
twogarlic marked this conversation as resolved.
Show resolved Hide resolved
onClick = { onButtonClick() },
enabled = isEnabled
) {
Text(
text = text,
color = textColor,
style = NoostakTheme.typography.t3Bold
twogarlic marked this conversation as resolved.
Show resolved Hide resolved
)
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3 : 코드가 길어지니 가독성 측면에서 효율성이 떨어지는 것 같아요. 저라면 제목, 요일, 날짜, 선택했을 때 나타나는 하이라이터 각각을 컴포넌트로 한번 더 빼내서 사용했을 것 같아요. 리팩 측면에서 한번 생각해보시고 분리하면 좋을 것 같네요

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 : 해당 파일 코리 중 제안한 코드들이 있을겁니다. 세부적으로 spacer, padding 등을 변경하며 코드를 실행하였을 때 달라진 프리뷰를 첨부합니다.(원형 하이라이터는 코리를 위해 활성화한 것임)
왼쪽이 원본 코드, 오른쪽은 제가 단 제안 코드를 적용했을 때의 화면입니다. 조금씩 영역과 여백의 차이를 확인할 수 있을 겁니다

스크린샷 2025-01-06 오전 1 20 42 스크린샷 2025-01-06 오전 1 19 54

아래의 피그마 GUI 예시에서 확인할 수 있듯이 디자인쌤들이 지정한 여백, 터치 영역 등을 마우스로 잘 체킹하여 파악하고 그와 유사하게 구현하는 연습을 하면 더 좋을 것 같네요!

스크린샷 2025-01-06 오전 1 23 03

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 : 해당 파일의 캘린더 프로세스 코드는 UI 코드가 조금 더 정리된 후에 확인하는 것이 나을 것 같아요. 코리 반영 및 리팩 후 다시 체킹할 수 있게 언급 부탁드려요

Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
package com.sopt.core.designsystem.component.calendar

import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import com.sopt.core.R
import com.sopt.core.designsystem.theme.NoostakTheme
import java.time.LocalDate
import java.time.YearMonth

@Composable
fun NoostakCalendar(
start: String,
end: String,
isSingleDate: Boolean,
isRangeSelected: (String, String) -> Unit,
modifier: Modifier = Modifier
) {
val typography = NoostakTheme.typography
val colors = NoostakTheme.colors

var year by remember { mutableStateOf(LocalDate.now().year) }
var month by remember { mutableStateOf(LocalDate.now().monthValue) }
var selectedDates by remember { mutableStateOf<List<String>>(emptyList()) }
var startDate by remember { mutableStateOf(start) }
var endDate by remember { mutableStateOf(end) }
var showMessage by remember { mutableStateOf(false) }

val yearMonth = YearMonth.of(year, month)
val totalDays = yearMonth.lengthOfMonth()
val firstDay = LocalDate.of(year, month, 1).dayOfWeek.value % 7

LaunchedEffect(isSingleDate) {
selectedDates = emptyList()
startDate = ""
endDate = ""
}

LaunchedEffect(showMessage) {
if (showMessage) {
kotlinx.coroutines.delay(3000)
showMessage = false
}
}

Column(modifier = modifier) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
twogarlic marked this conversation as resolved.
Show resolved Hide resolved
Image(
painter = painterResource(id = R.drawable.ic_calendar_back),
contentDescription = null,
modifier = Modifier
.size(16.dp)
.clickable {
if (month == 1) {
year -= 1
month = 12
} else {
month -= 1
}
}
Comment on lines +97 to +103
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: 1월에서 그 전으로 가면 12월... 바로 이해가 가유 ㅋㅋㅋㅋㅋㅋㅋㅋㅋ

)
Spacer(modifier = Modifier.width(10.dp))
Text(
text = "$year 년 $month 월",
style = typography.b1SemiBold,
color = colors.gray900,
textAlign = TextAlign.Center,
)
Spacer(modifier = Modifier.width(10.dp))
twogarlic marked this conversation as resolved.
Show resolved Hide resolved
Image(
painter = painterResource(id = R.drawable.ic_calendar_front),
contentDescription = null,
modifier = Modifier
.size(16.dp)
.clickable {
if (month == 12) {
year += 1
month = 1
} else {
month += 1
}
}
)
}

Spacer(modifier = Modifier.height(30.dp))

Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3 : 넣으신 이유가 있나요?

) {
listOf("일", "월", "화", "수", "목", "금", "토").forEach { day ->
twogarlic marked this conversation as resolved.
Show resolved Hide resolved
Text(
text = day,
style = typography.c2SemiBold,
textAlign = TextAlign.Center,
color = colors.gray600,
modifier = Modifier.weight(1f)
twogarlic marked this conversation as resolved.
Show resolved Hide resolved
)
}
}

Spacer(modifier = Modifier.height(16.dp))
twogarlic marked this conversation as resolved.
Show resolved Hide resolved
Column(verticalArrangement = Arrangement.spacedBy(15.dp)) {
var day = 1
for (week in 0..5) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
(0..6).forEach { dayOfWeek ->
val dateText = when {
week == 0 && dayOfWeek < firstDay -> ""
day > totalDays -> ""
else -> (day++).toString()
}

val dateValue = "$year-${month.toString().padStart(2, '0')}-${dateText.padStart(2, '0')}"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3 : padStart()는 무슨 역할을 하나요? UI 상에서는 해당 부분이 안쓰인 것 같은데 꼭 자리수를 채워야 코드가 동작하는 것인가요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

연속된 날짜 선택할때 더 늦은 날짜를 먼저 누르고 더 빠른 날짜(8일 이상 차이나는)를 먼저 누를경우, 늦은 날짜를 끝마칠 날짜로 정하고 그 날짜를 기준으로 7일 차이나는 날짜를 시작날짜로 정하도록 계산할때 사용하고있는데 혹시 다른 방법 있을까요 ㅠㅠㅠㅠㅠ...... ... ...


val isSelected = dateValue in selectedDates
val isRange = !isSingleDate &&
dateText.isNotEmpty() &&
startDate.isNotEmpty() &&
endDate.isNotEmpty() &&
LocalDate.parse(dateValue) in LocalDate.parse(startDate)..LocalDate.parse(endDate)

val isStart = dateValue == startDate
val isEnd = dateValue == endDate

Box(
modifier = Modifier
.weight(1f)
.height(40.dp),
twogarlic marked this conversation as resolved.
Show resolved Hide resolved
contentAlignment = Alignment.Center
) {
when {
isSelected -> {
Box(
modifier = Modifier
.size(40.dp)
.background(
color = colors.blue300,
shape = androidx.compose.foundation.shape.CircleShape
twogarlic marked this conversation as resolved.
Show resolved Hide resolved
)
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 : 코드상 재사용되는 컴포넌트로 확인되는데 따로 빼서 호출해서 사용하면 더 좋을 것 같은데요

}
isRange && !isStart && !isEnd -> {
Box(
modifier = Modifier
.fillMaxWidth()
.height(40.dp)
.background(colors.blue100)
)
Comment on lines +184 to +189
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 : 또한 동일 코드에서 재사용되므로 빼서 호출해서 사용하면 좋을 것 같습니다. 인자로 padding 값 추가하구요

}
isStart -> {
Box(
modifier = Modifier
.fillMaxWidth()
.height(40.dp)
.padding(start = 20.dp)
.background(colors.blue100)
)
}
isEnd -> {
Box(
modifier = Modifier
.fillMaxWidth()
.height(40.dp)
.padding(end = 20.dp)
.background(colors.blue100)
)
}
}

if (isStart || isEnd) {
Box(
modifier = Modifier
.size(40.dp)
.background(
color = colors.blue300,
shape = androidx.compose.foundation.shape.CircleShape
)
)
}

Text(
text = dateText,
style = typography.c3Regular,
textAlign = TextAlign.Center,
color = colors.gray900,
modifier = Modifier.clickable(enabled = dateText.isNotEmpty()) {
twogarlic marked this conversation as resolved.
Show resolved Hide resolved
if (isSingleDate) {
if (dateValue in selectedDates) {
selectedDates = selectedDates - dateValue
} else {
if (selectedDates.size < 7) {
selectedDates = selectedDates + dateValue
} else {
showMessage = true
}
}
} else {
val selectedDate = LocalDate.parse(dateValue)
if (startDate.isEmpty() || (startDate.isNotEmpty() && endDate.isNotEmpty())) {
startDate = dateValue
endDate = ""
} else {
val tempStart = LocalDate.parse(startDate)
val tempEnd = selectedDate
if (tempStart.isAfter(tempEnd)) {
if (tempStart.minusDays(7) > tempEnd) {
startDate = tempStart.minusDays(7).toString()
endDate = tempStart.toString()
showMessage = true
} else {
endDate = tempStart.toString()
startDate = tempEnd.toString()
}
} else {
if (tempStart.plusDays(7) < tempEnd) {
endDate = tempStart.plusDays(7).toString()
startDate = tempStart.toString()
showMessage = true
} else {
startDate = tempStart.toString()
endDate = tempEnd.toString()
}
}
}
isRangeSelected(startDate, endDate)
}
}
)
}
}
}
}
}

if (showMessage) {
Spacer(modifier = Modifier.height(1.dp))
Box(
modifier = Modifier
.width(195.dp)
.height(42.dp)
.align(Alignment.CenterHorizontally)
.background(
color = colors.pink,
shape = androidx.compose.foundation.shape.RoundedCornerShape(30.dp)
twogarlic marked this conversation as resolved.
Show resolved Hide resolved
twogarlic marked this conversation as resolved.
Show resolved Hide resolved
)
.padding(8.dp),
contentAlignment = Alignment.Center
) {
twogarlic marked this conversation as resolved.
Show resolved Hide resolved
Text(
text = "최대 7일까지 선택할 수 있어요",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: extract string plz

style = typography.c2SemiBold,
color = colors.red01,
textAlign = TextAlign.Center
)
}
}
}
}
twogarlic marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.sopt.core.designsystem.component.chip

import androidx.compose.ui.graphics.Color
import androidx.compose.runtime.Composable
import androidx.compose.ui.unit.dp
import com.sopt.core.designsystem.theme.NoostakTheme


@Composable
fun NoostakCategoryChip2(
twogarlic marked this conversation as resolved.
Show resolved Hide resolved
text: String,
textColor: Color,
backgroundColor: Color,
borderColor: Color
) {
NoostakChip(
text = text,
textStyle = NoostakTheme.typography.b4SemiBold,
textColor = textColor,
backgroundColor = backgroundColor,
borderColor = borderColor,
horizontalPaddingValues = 15.dp,
verticalPaddingValues = 6.dp
twogarlic marked this conversation as resolved.
Show resolved Hide resolved
)
}
Loading
Loading