-
Notifications
You must be signed in to change notification settings - Fork 9
[FIX/#1591] 앱잼탬프 QA 사항 반영 #1598
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
base: develop
Are you sure you want to change the base?
Changes from all commits
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 |
|---|---|---|
|
|
@@ -130,10 +130,11 @@ internal fun MissionDetailRoute( | |
| } | ||
| } | ||
|
|
||
| LaunchedEffect(!uiState.isLoading, progress) { | ||
| if (progress >= 0.99f && !uiState.isLoading) { | ||
| LaunchedEffect(showPostSubmissionBadge, !uiState.isLoading, progress) { | ||
| if (showPostSubmissionBadge && progress >= 0.99f && !uiState.isLoading) { | ||
| delay(500L) | ||
| viewModel.updateShowPostSubmissionBadge() | ||
| navigateUp() | ||
| } | ||
| } | ||
|
Comment on lines
+133
to
139
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.
대신 참고: LaunchedEffect(showPostSubmissionBadge) {
if (showPostSubmissionBadge) {
snapshotFlow { progress >= 0.99f && !uiState.isLoading }
.first { it }
delay(500L)
viewModel.updateShowPostSubmissionBadge()
navigateUp()
}
} |
||
|
|
||
|
|
@@ -148,7 +149,8 @@ internal fun MissionDetailRoute( | |
| }, | ||
| onDatePickerClick = { isDatePickerVisible = true }, | ||
| onMemoChange = viewModel::updateContent, | ||
| onCompleteButtonClick = viewModel::handleSubmit | ||
| onCompleteButtonClick = viewModel::handleSubmit, | ||
| isSubmitEnabled = uiState.isSubmitEnabled, | ||
| ) | ||
| } else { | ||
| MissionDetailScreen( | ||
|
|
@@ -185,7 +187,8 @@ internal fun MissionDetailRoute( | |
|
|
||
| DetailViewType.EDIT -> viewModel.handleSubmit() | ||
| } | ||
| } | ||
| }, | ||
| isSubmitEnabled = uiState.isSubmitEnabled, | ||
| ) | ||
| } | ||
|
|
||
|
|
@@ -249,7 +252,8 @@ private fun MyEmptyMissionDetailScreen( | |
| onClickZoomIn: (String) -> Unit, | ||
| onDatePickerClick: () -> Unit, | ||
| onMemoChange: (String) -> Unit, | ||
| onCompleteButtonClick: () -> Unit | ||
| onCompleteButtonClick: () -> Unit, | ||
| isSubmitEnabled: Boolean, | ||
| ) { | ||
| val scrollState = rememberScrollState() | ||
|
|
||
|
|
@@ -306,6 +310,7 @@ private fun MyEmptyMissionDetailScreen( | |
| AppjamtampButton( | ||
| text = "미션 완료", | ||
| onClicked = onCompleteButtonClick, | ||
| isEnabled = isSubmitEnabled, | ||
| modifier = Modifier | ||
| .fillMaxWidth() | ||
| .padding(bottom = 20.dp) | ||
|
|
@@ -322,7 +327,8 @@ private fun MissionDetailScreen( | |
| onClickZoomIn: (String) -> Unit, | ||
| onDatePickerClick: () -> Unit, | ||
| onMemoChange: (String) -> Unit, | ||
| onActionButtonClick: () -> Unit | ||
| onActionButtonClick: () -> Unit, | ||
| isSubmitEnabled: Boolean, | ||
| ) { | ||
| val scrollState = rememberScrollState() | ||
| var isEditable by remember(uiState.viewType) { mutableStateOf(uiState.viewType == DetailViewType.EDIT) } | ||
|
|
@@ -436,6 +442,7 @@ private fun MissionDetailScreen( | |
| AppjamtampButton( | ||
| text = "미션 완료", | ||
| onClicked = onActionButtonClick, | ||
| isEnabled = isSubmitEnabled, | ||
| modifier = Modifier | ||
| .fillMaxWidth() | ||
| .padding(bottom = 20.dp) | ||
|
|
@@ -456,7 +463,8 @@ private fun MyEmptyMissionDetailScreenPreview() { | |
| onClickZoomIn = {}, | ||
| onDatePickerClick = {}, | ||
| onMemoChange = {}, | ||
| onCompleteButtonClick = {} | ||
| onCompleteButtonClick = {}, | ||
| isSubmitEnabled = true, | ||
| ) | ||
| } | ||
| } | ||
|
|
@@ -473,7 +481,8 @@ private fun MyMissionDetailScreenPreview() { | |
| onDatePickerClick = {}, | ||
| onMemoChange = {}, | ||
| onActionButtonClick = {}, | ||
| onToolbarIconClick = {} | ||
| onToolbarIconClick = {}, | ||
| isSubmitEnabled = true, | ||
| ) | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -129,6 +129,9 @@ internal class MissionDetailViewModel @Inject constructor( | |
| imageModel = ImageModel.Remote(stamp.images), | ||
| date = stamp.activityDate, | ||
| content = stamp.contents, | ||
| initSnapshotImageModel = ImageModel.Remote(stamp.images), | ||
| initSnapshotDate = stamp.activityDate, | ||
| initSnapshotContent = stamp.contents, | ||
| teamName = stamp.teamName, | ||
| stampId = stamp.stampId, | ||
| writer = User( | ||
|
|
@@ -260,7 +263,10 @@ internal class MissionDetailViewModel @Inject constructor( | |
| _missionDetailState.update { | ||
| it.copy( | ||
| isLoading = false, | ||
| viewType = DetailViewType.COMPLETE | ||
| viewType = DetailViewType.COMPLETE, | ||
| initSnapshotImageModel = ImageModel.Remote(imageModel.url), | ||
| initSnapshotDate = date, | ||
| initSnapshotContent = content, | ||
|
Comment on lines
+267
to
+269
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.
이로 인해 사용자가 새 미션을 제출한 직후 상세 화면에서 바로 수정을 시도할 경우, 초기 스냅샷 값이 여전히 비어 있는 상태(기본값)로 유지되어
|
||
| ) | ||
| } | ||
| }.onFailure { e -> | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -157,24 +157,27 @@ private fun String?.toRelativeTime(): String { | |
|
|
||
| val dateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.KOREA) | ||
| dateFormat.timeZone = TimeZone.getTimeZone("Asia/Seoul") | ||
| val monthDayFormat = SimpleDateFormat("M월d일", Locale.KOREA).apply { | ||
| timeZone = TimeZone.getTimeZone("Asia/Seoul") | ||
| } | ||
|
|
||
| val date = dateFormat.parse(this) ?: return "" | ||
| val date = runCatching { dateFormat.parse(this) }.getOrNull() ?: return "" | ||
| val currentDate = Date() | ||
|
|
||
| val diffMillis = currentDate.time - date.time | ||
| if (diffMillis < 0) return "1분 전" | ||
| if (diffMillis < 0) return "방금 전" | ||
|
|
||
| val minutes = TimeUnit.MILLISECONDS.toMinutes(diffMillis) | ||
| val hours = TimeUnit.MILLISECONDS.toHours(diffMillis) | ||
| val days = TimeUnit.MILLISECONDS.toDays(diffMillis) | ||
|
|
||
| return when { | ||
| minutes == 0L -> "1분 전" | ||
| minutes in 1..59 -> "${minutes}분 전" | ||
| hours in 1..24 -> "${hours}시간 전" | ||
| else -> { | ||
| val days = TimeUnit.MILLISECONDS.toDays(diffMillis) | ||
| "${days}일 전" | ||
| } | ||
| minutes < 10L -> "방금 전" | ||
| minutes < 60L -> "${minutes}분 전" | ||
| hours < 25L -> "${hours}시간 전" | ||
| days < 7L -> "${days}일 전" | ||
| days < 35L -> "${days / 7}주 전" | ||
| else -> monthDayFormat.format(date) | ||
|
Comment on lines
+179
to
+180
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. 4주 이후 포맷 요구사항과 분기 조건이 어긋납니다. Line 179의 수정 제안 diff- days < 35L -> "${days / 7}주 전"
+ days < 28L -> "${days / 7}주 전"
else -> monthDayFormat.format(date)🤖 Prompt for AI Agents |
||
| } | ||
| } | ||
|
Comment on lines
158
to
182
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.
성능을 최적화하고 불필요한 객체 할당을 피하기 위해 포맷터를 캐싱하는 것이 좋습니다. val date = runCatching { Holder.dateFormat.get().parse(this) }.getOrNull() ?: return ""
val currentDate = Date()
val diffMillis = currentDate.time - date.time
if (diffMillis < 0) return "방금 전"
val minutes = TimeUnit.MILLISECONDS.toMinutes(diffMillis)
val hours = TimeUnit.MILLISECONDS.toHours(diffMillis)
val days = TimeUnit.MILLISECONDS.toDays(diffMillis)
return when {
minutes < 10L -> "방금 전"
minutes < 60L -> "${minutes}분 전"
hours < 25L -> "${hours}시간 전"
days < 7L -> "${days}일 전"
days < 35L -> "${days / 7}주 전"
else -> Holder.monthDayFormat.get().format(date)
}
}
private object Holder {
val dateFormat = object : ThreadLocal<SimpleDateFormat>() {
override fun initialValue() = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.KOREA).apply {
timeZone = TimeZone.getTimeZone("Asia/Seoul")
}
}
val monthDayFormat = object : ThreadLocal<SimpleDateFormat>() {
override fun initialValue() = SimpleDateFormat("M월d일", Locale.KOREA).apply {
timeZone = TimeZone.getTimeZone("Asia/Seoul")
}
}
} |
||
|
|
||
|
|
||
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.
isEnabled가 false일 때 버튼은 시각적으로 비활성화되지만, 클릭 한정자(noRippleClickable)는 여전히 연결되어 있어 클릭 이벤트를 가로챕니다(람다 내부에서 아무 동작도 하지 않더라도). 이는 TalkBack과 같은 접근성 서비스나 키보드 탐색 시 비활성화된 버튼이 여전히 클릭 가능한 것처럼 인식되는 문제를 유발할 수 있습니다.버튼이 비활성화되었을 때는 클릭 리스너 자체가 연결되지 않도록
.let을 사용하여noRippleClickable한정자를 조건부로 적용하는 것이 좋습니다..background( color = if (isEnabled) SoptTheme.colors.primary else SoptTheme.colors.onSurface300, shape = RoundedCornerShape(9.dp), ) .let { if (isEnabled) it.noRippleClickable(onClick = onClicked) else it }