From 2f371afca843d798f54491b6b5339f48c580ca7e Mon Sep 17 00:00:00 2001 From: chanho0908 Date: Thu, 26 Feb 2026 16:27:48 +0900 Subject: [PATCH 01/25] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refactor:=20`action?= =?UTF-8?q?=5Fsting`=20=EB=A6=AC=EC=86=8C=EC=8A=A4=EB=AA=85=EC=9D=84=20`ac?= =?UTF-8?q?tion=5Fpoke`=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/design-system/src/main/res/values/strings.xml | 4 ++-- .../main/java/com/twix/home/component/GoalVerifications.kt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/design-system/src/main/res/values/strings.xml b/core/design-system/src/main/res/values/strings.xml index 3cabb0b8..7c49826f 100644 --- a/core/design-system/src/main/res/values/strings.xml +++ b/core/design-system/src/main/res/values/strings.xml @@ -44,8 +44,8 @@ 끝내기 이뤘어요 탈퇴하기 - 찌르기 - 찌르기! + 찌르기 + 찌르기! 오늘 우리 목표 diff --git a/feature/main/src/main/java/com/twix/home/component/GoalVerifications.kt b/feature/main/src/main/java/com/twix/home/component/GoalVerifications.kt index 8ff1f6d9..e1b25212 100644 --- a/feature/main/src/main/java/com/twix/home/component/GoalVerifications.kt +++ b/feature/main/src/main/java/com/twix/home/component/GoalVerifications.kt @@ -91,7 +91,7 @@ private fun EmptyContent( ) AppRoundButton( - text = stringResource(R.string.action_sting_emphasized), + text = stringResource(R.string.action_poke_emphasized), textColor = GrayColor.C500, textStyle = AppTextStyle.C2, backgroundColor = CommonColor.White, From 94b36e387895602c93f144b4569562d502ab3f3d Mon Sep 17 00:00:00 2001 From: chanho0908 Date: Thu, 26 Feb 2026 16:28:23 +0900 Subject: [PATCH 02/25] =?UTF-8?q?=E2=9C=A8=20Feat:=20=EC=9D=B8=EC=A6=9D=20?= =?UTF-8?q?=EC=83=81=EC=84=B8=20=ED=99=94=EB=A9=B4=20'=EC=B0=8C=EB=A5=B4?= =?UTF-8?q?=EA=B8=B0'=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../detail/TaskCertificationDetail.kt | 13 +++++++++---- .../detail/TaskCertificationDetailViewModel.kt | 12 +++++++++++- .../component/TaskCertificationCardContent.kt | 6 +++--- .../contract/TaskCertificationDetailIntent.kt | 2 +- .../contract/TaskCertificationDetailSideEffect.kt | 4 ++++ 5 files changed, 28 insertions(+), 9 deletions(-) diff --git a/feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetail.kt b/feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetail.kt index 268d8ccf..049011d1 100644 --- a/feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetail.kt +++ b/feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetail.kt @@ -64,6 +64,11 @@ fun TaskCertificationDetailRoute( ToastData(currentContext.getString(sideEffect.message), sideEffect.type), ) } + is TaskCertificationDetailSideEffect.ShowPokeToast -> { + toastManager.tryShow( + ToastData(sideEffect.message, ToastType.SUCCESS), + ) + } } } @@ -110,7 +115,7 @@ fun TaskCertificationDetailRoute( permissionLauncher.launch(Manifest.permission.CAMERA) } }, - onClickSting = { viewModel.dispatch(TaskCertificationDetailIntent.Sting) }, + onPoke = { viewModel.dispatch(TaskCertificationDetailIntent.Poke) }, onSwipe = { viewModel.dispatch(TaskCertificationDetailIntent.SwipeCard) }, ) } @@ -122,7 +127,7 @@ fun TaskCertificationDetailScreen( onClickModify: () -> Unit, onClickReaction: (GoalReactionType) -> Unit, onClickUpload: () -> Unit, - onClickSting: () -> Unit, + onPoke: () -> Unit, onSwipe: () -> Unit, ) { Scaffold( @@ -147,7 +152,7 @@ fun TaskCertificationDetailScreen( uiState = uiState, onSwipe = onSwipe, onClickUpload = onClickUpload, - onClickSting = onClickSting, + onPoke = onPoke, ) if (uiState.canReaction) { @@ -173,7 +178,7 @@ private fun TaskCertificationDetailScreenPreview( onClickModify = {}, onClickReaction = {}, onClickUpload = {}, - onClickSting = {}, + onPoke = {}, onSwipe = {}, ) } diff --git a/feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetailViewModel.kt b/feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetailViewModel.kt index 6b03a2ab..9de14246 100644 --- a/feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetailViewModel.kt +++ b/feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetailViewModel.kt @@ -7,6 +7,7 @@ import com.twix.designsystem.components.toast.model.ToastType import com.twix.domain.model.enums.BetweenUs import com.twix.domain.model.enums.GoalReactionType import com.twix.domain.repository.PhotoLogRepository +import com.twix.domain.repository.PokeRepository import com.twix.navigation.NavRoutes import com.twix.task_certification.detail.contract.TaskCertificationDetailIntent import com.twix.task_certification.detail.contract.TaskCertificationDetailSideEffect @@ -26,6 +27,7 @@ import java.time.LocalDate class TaskCertificationDetailViewModel( private val photologRepository: PhotoLogRepository, + private val pokeRepository: PokeRepository, private val detailRefreshBus: TaskCertificationRefreshBus, private val goalRefreshBus: GoalRefreshBus, savedStateHandle: SavedStateHandle, @@ -119,7 +121,7 @@ class TaskCertificationDetailViewModel( override suspend fun handleIntent(intent: TaskCertificationDetailIntent) { when (intent) { is TaskCertificationDetailIntent.Reaction -> reduceReaction(intent.type) - TaskCertificationDetailIntent.Sting -> TODO("찌르기 API 연동") + TaskCertificationDetailIntent.Poke -> pokeToPartner() TaskCertificationDetailIntent.SwipeCard -> reduceShownCard() } } @@ -130,6 +132,14 @@ class TaskCertificationDetailViewModel( reactionFlow.tryEmit(reaction) } + private fun pokeToPartner() { + launchResult( + block = { pokeRepository.pokeGoal(argGoalId) }, + onSuccess = { tryEmitSideEffect(TaskCertificationDetailSideEffect.ShowPokeToast(it.message)) }, + onError = { showToast(R.string.toast_poke_goal_failed, ToastType.ERROR) }, + ) + } + private fun reduceShownCard() { reduce { toggleBetweenUs() } } diff --git a/feature/task-certification/src/main/java/com/twix/task_certification/detail/component/TaskCertificationCardContent.kt b/feature/task-certification/src/main/java/com/twix/task_certification/detail/component/TaskCertificationCardContent.kt index c5ecc221..b98e0bd8 100644 --- a/feature/task-certification/src/main/java/com/twix/task_certification/detail/component/TaskCertificationCardContent.kt +++ b/feature/task-certification/src/main/java/com/twix/task_certification/detail/component/TaskCertificationCardContent.kt @@ -17,7 +17,7 @@ internal fun TaskCertificationCardContent( uiState: TaskCertificationDetailUiState, onSwipe: () -> Unit, onClickUpload: () -> Unit, - onClickSting: () -> Unit, + onPoke: () -> Unit, ) { Box(Modifier.fillMaxWidth()) { BackgroundCard( @@ -26,10 +26,10 @@ internal fun TaskCertificationCardContent( buttonTitle = when (uiState.currentShow) { BetweenUs.ME -> stringResource(R.string.task_certification_take_picture) - BetweenUs.PARTNER -> stringResource(R.string.action_sting) + BetweenUs.PARTNER -> stringResource(R.string.action_poke) }, rotation = if (uiState.isDisplayedMyPhotolog) -8f else 0f, - onClick = if (uiState.isDisplayedMyPhotolog) onClickUpload else onClickSting, + onClick = if (uiState.isDisplayedMyPhotolog) onClickUpload else onPoke, ) SwipeableCard( diff --git a/feature/task-certification/src/main/java/com/twix/task_certification/detail/contract/TaskCertificationDetailIntent.kt b/feature/task-certification/src/main/java/com/twix/task_certification/detail/contract/TaskCertificationDetailIntent.kt index 650100dd..be025f04 100644 --- a/feature/task-certification/src/main/java/com/twix/task_certification/detail/contract/TaskCertificationDetailIntent.kt +++ b/feature/task-certification/src/main/java/com/twix/task_certification/detail/contract/TaskCertificationDetailIntent.kt @@ -8,7 +8,7 @@ sealed interface TaskCertificationDetailIntent : Intent { val type: GoalReactionType, ) : TaskCertificationDetailIntent - data object Sting : TaskCertificationDetailIntent + data object Poke : TaskCertificationDetailIntent data object SwipeCard : TaskCertificationDetailIntent } diff --git a/feature/task-certification/src/main/java/com/twix/task_certification/detail/contract/TaskCertificationDetailSideEffect.kt b/feature/task-certification/src/main/java/com/twix/task_certification/detail/contract/TaskCertificationDetailSideEffect.kt index 202348ef..92532bfb 100644 --- a/feature/task-certification/src/main/java/com/twix/task_certification/detail/contract/TaskCertificationDetailSideEffect.kt +++ b/feature/task-certification/src/main/java/com/twix/task_certification/detail/contract/TaskCertificationDetailSideEffect.kt @@ -8,4 +8,8 @@ sealed interface TaskCertificationDetailSideEffect : SideEffect { val message: Int, val type: ToastType, ) : TaskCertificationDetailSideEffect + + data class ShowPokeToast( + val message: String, + ) : TaskCertificationDetailSideEffect } From 73c72a70f078e62a6162d8cb1da433fcc84cd88c Mon Sep 17 00:00:00 2001 From: chanho0908 Date: Thu, 26 Feb 2026 19:49:03 +0900 Subject: [PATCH 03/25] =?UTF-8?q?=E2=9C=A8=20Feat:=20=EC=9D=B8=EC=A6=9D?= =?UTF-8?q?=EC=83=B7=20=ED=99=94=EB=A9=B4=EC=9A=A9=20=EC=B0=8C=EB=A5=B4?= =?UTF-8?q?=EA=B8=B0=20=EC=95=A1=EC=85=98=20=EC=95=84=EC=9D=B4=EC=BD=98=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `ic_photolog_action_poke.xml` 벡터 드로어블 리소스 추가 --- .../res/drawable/ic_photolog_action_poke.xml | 139 ++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 core/design-system/src/main/res/drawable/ic_photolog_action_poke.xml diff --git a/core/design-system/src/main/res/drawable/ic_photolog_action_poke.xml b/core/design-system/src/main/res/drawable/ic_photolog_action_poke.xml new file mode 100644 index 00000000..2d58e737 --- /dev/null +++ b/core/design-system/src/main/res/drawable/ic_photolog_action_poke.xml @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + + + + + + From 85c3dad8d7206cd50f053762d2ce9e50c59ebb5e Mon Sep 17 00:00:00 2001 From: chanho0908 Date: Thu, 26 Feb 2026 19:50:34 +0900 Subject: [PATCH 04/25] =?UTF-8?q?=E2=9C=A8=20Feat:=20=EC=A2=85=EB=A3=8C?= =?UTF-8?q?=EB=90=9C=20=EB=AA=A9=ED=91=9C=20=EC=9D=B8=EC=A6=9D/=EC=B0=8C?= =?UTF-8?q?=EB=A5=B4=EA=B8=B0=20=EB=B9=84=ED=99=9C=EC=84=B1=ED=99=94=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/photolog/BackgroundCard.kt | 25 ++++++++++--------- .../java/com/twix/navigation/NavRoutes.kt | 6 +++-- .../twix/stats/detail/StatsDetailScreen.kt | 3 ++- .../twix/stats/detail/StatsDetailViewModel.kt | 1 + .../detail/contract/StatsDetailSideEffect.kt | 1 + .../detail/navigation/StatsDetailGraph.kt | 3 ++- .../TaskCertificationDetailViewModel.kt | 5 +++- .../component/TaskCertificationCardContent.kt | 6 ++--- .../TaskCertificationDetailUiState.kt | 6 +++++ .../navigation/TaskCertificationGraph.kt | 4 +++ 10 files changed, 40 insertions(+), 20 deletions(-) diff --git a/core/design-system/src/main/java/com/twix/designsystem/components/photolog/BackgroundCard.kt b/core/design-system/src/main/java/com/twix/designsystem/components/photolog/BackgroundCard.kt index ab898f48..3620bc96 100644 --- a/core/design-system/src/main/java/com/twix/designsystem/components/photolog/BackgroundCard.kt +++ b/core/design-system/src/main/java/com/twix/designsystem/components/photolog/BackgroundCard.kt @@ -8,6 +8,7 @@ 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.layout.wrapContentSize import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -27,19 +28,19 @@ import com.twix.ui.extension.noRippleClickable @Composable fun BackgroundCard( - isCertificated: Boolean, uploadedAt: String, - buttonTitle: String, - onClick: () -> Unit, + actionLabel: String, rotation: Float, + onClickAction: () -> Unit, + showActionButton: Boolean, ) { - Column { + Column(Modifier.wrapContentSize()) { PhotologCard( background = GrayColor.C200, borderColor = GrayColor.C500, rotation = rotation, ) - if (isCertificated) { + if (!showActionButton) { AppText( text = uploadedAt, style = AppTextStyle.B4, @@ -60,19 +61,19 @@ fun BackgroundCard( Modifier .width(150.dp) .height(74.dp) - .noRippleClickable { onClick() }, - text = buttonTitle, + .noRippleClickable { onClickAction() }, + text = actionLabel, textColor = GrayColor.C500, backgroundColor = CommonColor.White, ) } Image( - imageVector = ImageVector.vectorResource(R.drawable.ic_keepi_sting), + imageVector = ImageVector.vectorResource(R.drawable.ic_photolog_action_poke), contentDescription = null, modifier = Modifier - .padding(end = 24.dp, top = 15.dp) + .padding(end = 16.dp, top = 15.dp) .align(Alignment.TopEnd), ) } @@ -85,10 +86,10 @@ fun BackgroundCard( fun PreviewBackgroundCard() { TwixTheme { BackgroundCard( - buttonTitle = stringResource(R.string.word_sting), + actionLabel = stringResource(R.string.word_sting), uploadedAt = "2023.10.31 23:59", - onClick = {}, - isCertificated = true, + onClickAction = {}, + showActionButton = true, rotation = -8f, ) } diff --git a/core/navigation/src/main/java/com/twix/navigation/NavRoutes.kt b/core/navigation/src/main/java/com/twix/navigation/NavRoutes.kt index 9285b53f..58b95b2b 100644 --- a/core/navigation/src/main/java/com/twix/navigation/NavRoutes.kt +++ b/core/navigation/src/main/java/com/twix/navigation/NavRoutes.kt @@ -35,16 +35,18 @@ sealed class NavRoutes( object TaskCertificationGraph : NavRoutes("task_certification_graph") object TaskCertificationDetailRoute : - NavRoutes("task_certification_detail/{goalId}/{date}/{betweenUs}") { + NavRoutes("task_certification_detail/{goalId}/{date}/{betweenUs}?isCompleted={isCompleted}") { const val ARG_GOAL_ID = "goalId" const val ARG_DATE = "date" const val ARG_BETWEEN_US = "betweenUs" + const val ARG_IS_COMPLETED = "isCompleted" fun createRoute( goalId: Long, date: LocalDate, betweenUs: String, - ) = "task_certification_detail/$goalId/$date/$betweenUs" + isCompleted: Boolean = false, + ) = "task_certification_detail/$goalId/$date/$betweenUs?isCompleted=$isCompleted" } object TaskCertificationRoute : NavRoutes("task_certification/{data}") { diff --git a/feature/stats/detail/src/main/java/com/twix/stats/detail/StatsDetailScreen.kt b/feature/stats/detail/src/main/java/com/twix/stats/detail/StatsDetailScreen.kt index 17477730..1b3b8f57 100644 --- a/feature/stats/detail/src/main/java/com/twix/stats/detail/StatsDetailScreen.kt +++ b/feature/stats/detail/src/main/java/com/twix/stats/detail/StatsDetailScreen.kt @@ -61,7 +61,7 @@ import java.time.LocalDate fun StatsDetailRoute( onBack: () -> Unit, navigateToGoalEditor: (Long) -> Unit, - navigateToTaskCertificationDetail: (Long, LocalDate, BetweenUs) -> Unit, + navigateToTaskCertificationDetail: (Long, LocalDate, BetweenUs, Boolean) -> Unit, toastManager: ToastManager = koinInject(), viewModel: StatsDetailViewModel = koinViewModel(), ) { @@ -79,6 +79,7 @@ fun StatsDetailRoute( sideEffect.goalId, sideEffect.date, sideEffect.betweenUs, + sideEffect.isCompleted, ) is StatsDetailSideEffect.ShowToast -> { toastManager.tryShow( diff --git a/feature/stats/detail/src/main/java/com/twix/stats/detail/StatsDetailViewModel.kt b/feature/stats/detail/src/main/java/com/twix/stats/detail/StatsDetailViewModel.kt index 8b3439d0..0dbc48a4 100644 --- a/feature/stats/detail/src/main/java/com/twix/stats/detail/StatsDetailViewModel.kt +++ b/feature/stats/detail/src/main/java/com/twix/stats/detail/StatsDetailViewModel.kt @@ -238,6 +238,7 @@ class StatsDetailViewModel( goalId = currentState.goalId, date = selectedDate, betweenUs = resolveBetweenUs(completedDate.date), + isCompleted = currentState.detail.isCompleted, ), ) } diff --git a/feature/stats/detail/src/main/java/com/twix/stats/detail/contract/StatsDetailSideEffect.kt b/feature/stats/detail/src/main/java/com/twix/stats/detail/contract/StatsDetailSideEffect.kt index a8777465..d7c2d393 100644 --- a/feature/stats/detail/src/main/java/com/twix/stats/detail/contract/StatsDetailSideEffect.kt +++ b/feature/stats/detail/src/main/java/com/twix/stats/detail/contract/StatsDetailSideEffect.kt @@ -21,5 +21,6 @@ sealed interface StatsDetailSideEffect : SideEffect { val goalId: Long, val date: LocalDate, val betweenUs: BetweenUs, + val isCompleted: Boolean, ) : StatsDetailSideEffect } diff --git a/feature/stats/detail/src/main/java/com/twix/stats/detail/navigation/StatsDetailGraph.kt b/feature/stats/detail/src/main/java/com/twix/stats/detail/navigation/StatsDetailGraph.kt index b2052d2c..ef12f777 100644 --- a/feature/stats/detail/src/main/java/com/twix/stats/detail/navigation/StatsDetailGraph.kt +++ b/feature/stats/detail/src/main/java/com/twix/stats/detail/navigation/StatsDetailGraph.kt @@ -36,12 +36,13 @@ object StatsDetailGraph : NavGraphContributor { launchSingleTop = true } }, - navigateToTaskCertificationDetail = { goalId, date, betweenUs -> + navigateToTaskCertificationDetail = { goalId, date, betweenUs, isCompleted -> val destination = NavRoutes.TaskCertificationDetailRoute.createRoute( goalId = goalId, date = date, betweenUs = betweenUs.name, + isCompleted = isCompleted, ) navController.navigate(destination) { launchSingleTop = true diff --git a/feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetailViewModel.kt b/feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetailViewModel.kt index 09021e67..826cc1a9 100644 --- a/feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetailViewModel.kt +++ b/feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetailViewModel.kt @@ -48,6 +48,9 @@ class TaskCertificationDetailViewModel( savedStateHandle[NavRoutes.TaskCertificationDetailRoute.ARG_BETWEEN_US] ?: error(BETWEEN_US_NOT_FOUND) + private val argIsCompleted: Boolean = + savedStateHandle[NavRoutes.TaskCertificationDetailRoute.ARG_IS_COMPLETED] ?: false + private var lastReaction: GoalReactionType? = null private val reactionFlow = @@ -65,7 +68,7 @@ class TaskCertificationDetailViewModel( private fun fetchPhotolog() { launchResult( block = { photologRepository.fetchPhotologs(argTargetDate, argGoalId) }, - onSuccess = { reduce { it.toUiState(argGoalId, argBetweenUs, argTargetDate) } }, + onSuccess = { reduce { it.toUiState(argGoalId, argBetweenUs, argTargetDate, argIsCompleted) } }, onError = { showToast(R.string.task_certification_detail_fetch_photolog_fail, ToastType.ERROR) }, diff --git a/feature/task-certification/src/main/java/com/twix/task_certification/detail/component/TaskCertificationCardContent.kt b/feature/task-certification/src/main/java/com/twix/task_certification/detail/component/TaskCertificationCardContent.kt index 8fd8ca27..1a59e509 100644 --- a/feature/task-certification/src/main/java/com/twix/task_certification/detail/component/TaskCertificationCardContent.kt +++ b/feature/task-certification/src/main/java/com/twix/task_certification/detail/component/TaskCertificationCardContent.kt @@ -21,15 +21,15 @@ internal fun TaskCertificationCardContent( ) { Box(Modifier.fillMaxWidth()) { BackgroundCard( - isCertificated = uiState.isDisplayedGoalCertificated, uploadedAt = uiState.displayedGoalUpdateAt, - buttonTitle = + actionLabel = when (uiState.currentShow) { BetweenUs.ME -> stringResource(R.string.task_certification_take_picture) BetweenUs.PARTNER -> stringResource(R.string.action_poke) }, rotation = if (uiState.isDisplayedMyPhotolog) -8f else 0f, - onClick = if (uiState.isDisplayedMyPhotolog) onClickUpload else onPoke, + onClickAction = if (uiState.isDisplayedMyPhotolog) onClickUpload else onPoke, + showActionButton = uiState.showActionButton, ) SwipeableCard( diff --git a/feature/task-certification/src/main/java/com/twix/task_certification/detail/contract/TaskCertificationDetailUiState.kt b/feature/task-certification/src/main/java/com/twix/task_certification/detail/contract/TaskCertificationDetailUiState.kt index a907b700..b571dae9 100644 --- a/feature/task-certification/src/main/java/com/twix/task_certification/detail/contract/TaskCertificationDetailUiState.kt +++ b/feature/task-certification/src/main/java/com/twix/task_certification/detail/contract/TaskCertificationDetailUiState.kt @@ -20,6 +20,7 @@ data class TaskCertificationDetailUiState( val icon: GoalIconType = GoalIconType.DEFAULT, val myPhotolog: PhotologDetail? = null, val partnerPhotolog: PhotologDetail? = null, + val isCompletedGoal: Boolean = false, /** * 초기값으로 인해 찌르기/업로드 버튼이 렌더링 되는 것을 막기 위한 변수 * */ @@ -80,12 +81,16 @@ data class TaskCertificationDetailUiState( val canReaction: Boolean get() = currentShow == BetweenUs.PARTNER && isDisplayedGoalCertificated + + val showActionButton: Boolean + get() = !isCompletedGoal && !isDisplayedGoalCertificated } fun PhotoLogs.toUiState( goalId: Long, betweenUs: String, selectedDate: LocalDate, + isCompletedGoal: Boolean, ): TaskCertificationDetailUiState { val currentGoalPhotolog = goals.firstOrNull { @@ -102,5 +107,6 @@ fun PhotoLogs.toUiState( icon = currentGoalPhotolog.icon, myPhotolog = currentGoalPhotolog.myPhotolog, partnerPhotolog = currentGoalPhotolog.partnerPhotolog, + isCompletedGoal = isCompletedGoal, ) } diff --git a/feature/task-certification/src/main/java/com/twix/task_certification/navigation/TaskCertificationGraph.kt b/feature/task-certification/src/main/java/com/twix/task_certification/navigation/TaskCertificationGraph.kt index 8890a49f..30cb6ed1 100644 --- a/feature/task-certification/src/main/java/com/twix/task_certification/navigation/TaskCertificationGraph.kt +++ b/feature/task-certification/src/main/java/com/twix/task_certification/navigation/TaskCertificationGraph.kt @@ -37,6 +37,10 @@ object TaskCertificationGraph : NavGraphContributor { navArgument(NavRoutes.TaskCertificationDetailRoute.ARG_BETWEEN_US) { type = NavType.StringType }, + navArgument(NavRoutes.TaskCertificationDetailRoute.ARG_IS_COMPLETED) { + type = NavType.BoolType + defaultValue = false + }, ), ) { TaskCertificationDetailRoute( From 55939d62e489d91c4553b4af816777537b5fe866 Mon Sep 17 00:00:00 2001 From: chanho0908 Date: Fri, 27 Feb 2026 00:05:10 +0900 Subject: [PATCH 05/25] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refactor:=20`Backgro?= =?UTF-8?q?undCard`=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EB=B6=88?= =?UTF-8?q?=ED=95=84=EC=9A=94=ED=95=9C=20=EB=A0=88=EC=9D=B4=EC=95=84?= =?UTF-8?q?=EC=9B=83=20=EC=86=8D=EC=84=B1=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../twix/designsystem/components/photolog/BackgroundCard.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/design-system/src/main/java/com/twix/designsystem/components/photolog/BackgroundCard.kt b/core/design-system/src/main/java/com/twix/designsystem/components/photolog/BackgroundCard.kt index 3620bc96..482eda29 100644 --- a/core/design-system/src/main/java/com/twix/designsystem/components/photolog/BackgroundCard.kt +++ b/core/design-system/src/main/java/com/twix/designsystem/components/photolog/BackgroundCard.kt @@ -8,7 +8,6 @@ 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.layout.wrapContentSize import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -34,7 +33,7 @@ fun BackgroundCard( onClickAction: () -> Unit, showActionButton: Boolean, ) { - Column(Modifier.wrapContentSize()) { + Column { PhotologCard( background = GrayColor.C200, borderColor = GrayColor.C500, From dd00550a3d9e8b747bc8b15fd81d930ebbd978b7 Mon Sep 17 00:00:00 2001 From: chanho0908 Date: Fri, 27 Feb 2026 00:06:06 +0900 Subject: [PATCH 06/25] =?UTF-8?q?=F0=9F=94=A5=20Style:=20`ic=5Fkeepi=5Fsti?= =?UTF-8?q?ng.xml`=20=EB=A6=AC=EC=86=8C=EC=8A=A4=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/res/drawable/ic_keepi_sting.xml | 118 ------------------ 1 file changed, 118 deletions(-) delete mode 100644 core/design-system/src/main/res/drawable/ic_keepi_sting.xml diff --git a/core/design-system/src/main/res/drawable/ic_keepi_sting.xml b/core/design-system/src/main/res/drawable/ic_keepi_sting.xml deleted file mode 100644 index ca28a97f..00000000 --- a/core/design-system/src/main/res/drawable/ic_keepi_sting.xml +++ /dev/null @@ -1,118 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - From 2ccbe3083da4d58e97d2b0c455e0c61109f8e588 Mon Sep 17 00:00:00 2001 From: chanho0908 Date: Fri, 27 Feb 2026 02:59:04 +0900 Subject: [PATCH 07/25] =?UTF-8?q?=F0=9F=8E=A8=20Style:=20`StatsDetailViewM?= =?UTF-8?q?odel`=20=EC=BD=94=EB=93=9C=20=ED=8F=AC=EB=A7=B7=ED=8C=85=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/twix/stats/detail/StatsDetailViewModel.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/feature/stats/detail/src/main/java/com/twix/stats/detail/StatsDetailViewModel.kt b/feature/stats/detail/src/main/java/com/twix/stats/detail/StatsDetailViewModel.kt index afb9641f..9e578d2e 100644 --- a/feature/stats/detail/src/main/java/com/twix/stats/detail/StatsDetailViewModel.kt +++ b/feature/stats/detail/src/main/java/com/twix/stats/detail/StatsDetailViewModel.kt @@ -41,8 +41,8 @@ class StatsDetailViewModel( private val statsRepository: StatsRepository, savedStateHandle: SavedStateHandle, ) : BaseViewModel( - StatsDetailUiState(), -) { + StatsDetailUiState(), + ) { private val argGoalId: Long = requireNotNull(savedStateHandle[NavRoutes.StatsDetailRoute.ARG_GOAL_ID]) { GOAL_ID_NOT_FOUND } From f0adc61596dd3a6c9680293411666d565f5d26e6 Mon Sep 17 00:00:00 2001 From: chanho0908 Date: Fri, 27 Feb 2026 03:16:16 +0900 Subject: [PATCH 08/25] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refactor:=20`TaskCer?= =?UTF-8?q?tificationDetailViewModel`=20=EB=82=B4=20`showToast`=20?= =?UTF-8?q?=ED=95=A8=EC=88=98=20suspend=20=EC=A0=84=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../detail/TaskCertificationDetailViewModel.kt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetailViewModel.kt b/feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetailViewModel.kt index 826cc1a9..5dec0b46 100644 --- a/feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetailViewModel.kt +++ b/feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetailViewModel.kt @@ -157,13 +157,11 @@ class TaskCertificationDetailViewModel( }, ) - private fun showToast( + private suspend fun showToast( message: Int, type: ToastType, ) { - viewModelScope.launch { - emitSideEffect(TaskCertificationDetailSideEffect.ShowToast(message, type)) - } + emitSideEffect(TaskCertificationDetailSideEffect.ShowToast(message, type)) } companion object { From aad26b1d39fc5150de6bf4cc817f9119c6ffd58f Mon Sep 17 00:00:00 2001 From: chanho0908 Date: Fri, 27 Feb 2026 10:37:11 +0900 Subject: [PATCH 09/25] =?UTF-8?q?=E2=9C=A8=20Feat:=20`ReactionEffect`=20?= =?UTF-8?q?=EC=95=A0=EB=8B=88=EB=A9=94=EC=9D=B4=EC=85=98=20=EC=A2=85?= =?UTF-8?q?=EB=A3=8C=20=EC=BD=9C=EB=B0=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../detail/component/reaction/ReactionEffect.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/feature/task-certification/src/main/java/com/twix/task_certification/detail/component/reaction/ReactionEffect.kt b/feature/task-certification/src/main/java/com/twix/task_certification/detail/component/reaction/ReactionEffect.kt index 696eb339..95ecbf97 100644 --- a/feature/task-certification/src/main/java/com/twix/task_certification/detail/component/reaction/ReactionEffect.kt +++ b/feature/task-certification/src/main/java/com/twix/task_certification/detail/component/reaction/ReactionEffect.kt @@ -33,6 +33,7 @@ fun ReactionEffect( targetReaction: ReactionUiModel?, modifier: Modifier = Modifier, spec: ReactionEffectSpec = ReactionEffectSpec(), + onFinished: () -> Unit = {}, ) { if (targetReaction == null) return @@ -59,6 +60,8 @@ fun ReactionEffect( particles.addAll(newParticles) + var remaining = newParticles.size + // 2. 파티클 애니메이션 실행 newParticles.forEach { particle -> scope.launch { @@ -145,6 +148,9 @@ fun ReactionEffect( ) particles.remove(particle) + + remaining -= 1 + if (remaining == 0) onFinished() } } } From 47dba7c88372f71d69b2273b6dc89576356a913d Mon Sep 17 00:00:00 2001 From: chanho0908 Date: Fri, 27 Feb 2026 10:38:22 +0900 Subject: [PATCH 10/25] =?UTF-8?q?=E2=9C=A8=20Feat:=20=EC=9D=B8=EC=A6=9D=20?= =?UTF-8?q?=EC=83=81=EC=84=B8=20=EB=82=B4=20=EB=A6=AC=EC=95=A1=EC=85=98=20?= =?UTF-8?q?=EC=9D=B8=ED=84=B0=EB=A0=89=EC=85=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../detail/TaskCertificationDetail.kt | 65 +++++++++++++------ .../TaskCertificationDetailViewModel.kt | 16 ++++- .../contract/TaskCertificationDetailIntent.kt | 2 + .../TaskCertificationDetailUiState.kt | 11 ++++ 4 files changed, 74 insertions(+), 20 deletions(-) diff --git a/feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetail.kt b/feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetail.kt index f171fa23..8aefc1e3 100644 --- a/feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetail.kt +++ b/feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetail.kt @@ -4,6 +4,7 @@ import android.Manifest import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.background +import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize @@ -14,6 +15,7 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp @@ -30,6 +32,8 @@ import com.twix.domain.model.enums.GoalReactionType import com.twix.task_certification.detail.component.TaskCertificationCardContent import com.twix.task_certification.detail.component.TaskCertificationDetailTopBar import com.twix.task_certification.detail.component.reaction.ReactionContent +import com.twix.task_certification.detail.component.reaction.ReactionEffect +import com.twix.task_certification.detail.component.reaction.ReactionEffectSpec import com.twix.task_certification.detail.contract.TaskCertificationDetailIntent import com.twix.task_certification.detail.contract.TaskCertificationDetailSideEffect import com.twix.task_certification.detail.contract.TaskCertificationDetailUiState @@ -62,6 +66,7 @@ fun TaskCertificationDetailRoute( ToastData(currentContext.getString(sideEffect.message), sideEffect.type), ) } + is TaskCertificationDetailSideEffect.ShowPokeToast -> { toastManager.tryShow( ToastData(sideEffect.message, ToastType.SUCCESS), @@ -101,26 +106,48 @@ fun TaskCertificationDetailRoute( } } - TaskCertificationDetailScreen( - uiState = uiState, - onBack = navigateToBack, - onClickModify = { - navigateToEditor( - uiState.goalId, - uiState.selectedDate, - ) - }, - onClickReaction = { viewModel.dispatch(TaskCertificationDetailIntent.Reaction(it)) }, - onClickUpload = { - if (currentContext.hasCameraPermission()) { - navigateToCertification(uiState.goalId, uiState.selectedDate) - } else { - permissionLauncher.launch(Manifest.permission.CAMERA) + BoxWithConstraints { + val density = LocalDensity.current + val screenHeightPx = with(density) { maxHeight.toPx() } + + TaskCertificationDetailScreen( + uiState = uiState, + onBack = navigateToBack, + onClickModify = { + navigateToEditor( + uiState.goalId, + uiState.selectedDate, + ) + }, + onClickReaction = { viewModel.dispatch(TaskCertificationDetailIntent.Reaction(it)) }, + onClickUpload = { + if (currentContext.hasCameraPermission()) { + navigateToCertification(uiState.goalId, uiState.selectedDate) + } else { + permissionLauncher.launch(Manifest.permission.CAMERA) + } + }, + onPoke = { viewModel.dispatch(TaskCertificationDetailIntent.Poke) }, + onSwipe = { viewModel.dispatch(TaskCertificationDetailIntent.SwipeCard) }, + ) + + if (uiState.showMyPhotologReaction) { + val model = uiState.myReaction + if (model != null) { + ReactionEffect( + targetReaction = model, + spec = + ReactionEffectSpec( + particleCount = 10, + travelDistanceRange = 500..screenHeightPx.toInt(), + ), + onFinished = { + viewModel.dispatch(TaskCertificationDetailIntent.MyReactionEffected) + }, + ) } - }, - onPoke = { viewModel.dispatch(TaskCertificationDetailIntent.Poke) }, - onSwipe = { viewModel.dispatch(TaskCertificationDetailIntent.SwipeCard) }, - ) + } + } } @Composable diff --git a/feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetailViewModel.kt b/feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetailViewModel.kt index 5dec0b46..79a6d614 100644 --- a/feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetailViewModel.kt +++ b/feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetailViewModel.kt @@ -68,7 +68,16 @@ class TaskCertificationDetailViewModel( private fun fetchPhotolog() { launchResult( block = { photologRepository.fetchPhotologs(argTargetDate, argGoalId) }, - onSuccess = { reduce { it.toUiState(argGoalId, argBetweenUs, argTargetDate, argIsCompleted) } }, + onSuccess = { + reduce { + it.toUiState( + argGoalId, + argBetweenUs, + argTargetDate, + argIsCompleted, + ) + } + }, onError = { showToast(R.string.task_certification_detail_fetch_photolog_fail, ToastType.ERROR) }, @@ -127,6 +136,7 @@ class TaskCertificationDetailViewModel( is TaskCertificationDetailIntent.Reaction -> reduceReaction(intent.type) TaskCertificationDetailIntent.Poke -> pokeToPartner() TaskCertificationDetailIntent.SwipeCard -> reduceShownCard() + TaskCertificationDetailIntent.MyReactionEffected -> reduceMyReactionShown() } } @@ -157,6 +167,10 @@ class TaskCertificationDetailViewModel( }, ) + private fun reduceMyReactionShown() { + reduce { copy(hasShownMyReaction = true) } + } + private suspend fun showToast( message: Int, type: ToastType, diff --git a/feature/task-certification/src/main/java/com/twix/task_certification/detail/contract/TaskCertificationDetailIntent.kt b/feature/task-certification/src/main/java/com/twix/task_certification/detail/contract/TaskCertificationDetailIntent.kt index be025f04..00e57ece 100644 --- a/feature/task-certification/src/main/java/com/twix/task_certification/detail/contract/TaskCertificationDetailIntent.kt +++ b/feature/task-certification/src/main/java/com/twix/task_certification/detail/contract/TaskCertificationDetailIntent.kt @@ -11,4 +11,6 @@ sealed interface TaskCertificationDetailIntent : Intent { data object Poke : TaskCertificationDetailIntent data object SwipeCard : TaskCertificationDetailIntent + + data object MyReactionEffected : TaskCertificationDetailIntent } diff --git a/feature/task-certification/src/main/java/com/twix/task_certification/detail/contract/TaskCertificationDetailUiState.kt b/feature/task-certification/src/main/java/com/twix/task_certification/detail/contract/TaskCertificationDetailUiState.kt index b571dae9..3fefb3a0 100644 --- a/feature/task-certification/src/main/java/com/twix/task_certification/detail/contract/TaskCertificationDetailUiState.kt +++ b/feature/task-certification/src/main/java/com/twix/task_certification/detail/contract/TaskCertificationDetailUiState.kt @@ -5,6 +5,7 @@ import com.twix.domain.model.enums.BetweenUs import com.twix.domain.model.enums.GoalIconType import com.twix.domain.model.photolog.PhotoLogs import com.twix.domain.model.photolog.PhotologDetail +import com.twix.task_certification.detail.component.reaction.ReactionUiModel import com.twix.ui.base.State import com.twix.util.RelativeTimeFormatter import java.time.LocalDate @@ -21,6 +22,7 @@ data class TaskCertificationDetailUiState( val myPhotolog: PhotologDetail? = null, val partnerPhotolog: PhotologDetail? = null, val isCompletedGoal: Boolean = false, + val hasShownMyReaction: Boolean = false, /** * 초기값으로 인해 찌르기/업로드 버튼이 렌더링 되는 것을 막기 위한 변수 * */ @@ -84,6 +86,15 @@ data class TaskCertificationDetailUiState( val showActionButton: Boolean get() = !isCompletedGoal && !isDisplayedGoalCertificated + + val showMyPhotologReaction: Boolean + get() = + !hasShownMyReaction && + isDisplayedMyPhotolog && + myPhotolog?.reaction != null + + val myReaction: ReactionUiModel? + get() = myPhotolog?.reaction?.let { ReactionUiModel.find(it) } } fun PhotoLogs.toUiState( From c3bb17c66f0305b95df7aa6d604e288f0be14bda Mon Sep 17 00:00:00 2001 From: chanho0908 Date: Fri, 27 Feb 2026 11:32:13 +0900 Subject: [PATCH 11/25] =?UTF-8?q?=F0=9F=94=A5=20Chore:=20=EC=A4=91?= =?UTF-8?q?=EB=B3=B5=20=EB=A6=AC=EC=95=A1=EC=85=98=20=EC=95=84=EC=9D=B4?= =?UTF-8?q?=EC=BD=98=20=EC=97=90=EC=85=8B=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/res/drawable/ic_keepi_angry.xml | 69 ----- .../src/main/res/drawable/ic_keepi_doubt.xml | 85 ------ .../src/main/res/drawable/ic_keepi_fuck.xml | 135 ---------- .../src/main/res/drawable/ic_keepi_happy.xml | 87 ------- .../src/main/res/drawable/ic_keepi_love.xml | 84 ------ .../main/res/drawable/ic_keepi_singing.xml | 242 ------------------ .../main/res/drawable/ic_keepi_trouble.xml | 125 --------- 7 files changed, 827 deletions(-) delete mode 100644 core/design-system/src/main/res/drawable/ic_keepi_angry.xml delete mode 100644 core/design-system/src/main/res/drawable/ic_keepi_doubt.xml delete mode 100644 core/design-system/src/main/res/drawable/ic_keepi_fuck.xml delete mode 100644 core/design-system/src/main/res/drawable/ic_keepi_happy.xml delete mode 100644 core/design-system/src/main/res/drawable/ic_keepi_love.xml delete mode 100644 core/design-system/src/main/res/drawable/ic_keepi_singing.xml delete mode 100644 core/design-system/src/main/res/drawable/ic_keepi_trouble.xml diff --git a/core/design-system/src/main/res/drawable/ic_keepi_angry.xml b/core/design-system/src/main/res/drawable/ic_keepi_angry.xml deleted file mode 100644 index 1a396e8c..00000000 --- a/core/design-system/src/main/res/drawable/ic_keepi_angry.xml +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/core/design-system/src/main/res/drawable/ic_keepi_doubt.xml b/core/design-system/src/main/res/drawable/ic_keepi_doubt.xml deleted file mode 100644 index 45601312..00000000 --- a/core/design-system/src/main/res/drawable/ic_keepi_doubt.xml +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/core/design-system/src/main/res/drawable/ic_keepi_fuck.xml b/core/design-system/src/main/res/drawable/ic_keepi_fuck.xml deleted file mode 100644 index 22d0db5f..00000000 --- a/core/design-system/src/main/res/drawable/ic_keepi_fuck.xml +++ /dev/null @@ -1,135 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/core/design-system/src/main/res/drawable/ic_keepi_happy.xml b/core/design-system/src/main/res/drawable/ic_keepi_happy.xml deleted file mode 100644 index ce8d791d..00000000 --- a/core/design-system/src/main/res/drawable/ic_keepi_happy.xml +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/core/design-system/src/main/res/drawable/ic_keepi_love.xml b/core/design-system/src/main/res/drawable/ic_keepi_love.xml deleted file mode 100644 index ef233362..00000000 --- a/core/design-system/src/main/res/drawable/ic_keepi_love.xml +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/core/design-system/src/main/res/drawable/ic_keepi_singing.xml b/core/design-system/src/main/res/drawable/ic_keepi_singing.xml deleted file mode 100644 index b2a6ae27..00000000 --- a/core/design-system/src/main/res/drawable/ic_keepi_singing.xml +++ /dev/null @@ -1,242 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/core/design-system/src/main/res/drawable/ic_keepi_trouble.xml b/core/design-system/src/main/res/drawable/ic_keepi_trouble.xml deleted file mode 100644 index 16ca9adf..00000000 --- a/core/design-system/src/main/res/drawable/ic_keepi_trouble.xml +++ /dev/null @@ -1,125 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 3e4896ad815ee3ab4f9e263ea6be4379494abe10 Mon Sep 17 00:00:00 2001 From: chanho0908 Date: Fri, 27 Feb 2026 11:38:59 +0900 Subject: [PATCH 12/25] =?UTF-8?q?=F0=9F=8E=A8=20Style:=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=20=ED=99=94=EB=A9=B4=20=EC=95=84=EC=9D=B4?= =?UTF-8?q?=EC=BD=98=20=EB=A6=AC=EC=86=8C=EC=8A=A4=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/res/drawable/ic_singing.xml | 326 ++++++++++++++++++ .../main/java/com/twix/login/LoginScreen.kt | 2 +- 2 files changed, 327 insertions(+), 1 deletion(-) create mode 100644 core/design-system/src/main/res/drawable/ic_singing.xml diff --git a/core/design-system/src/main/res/drawable/ic_singing.xml b/core/design-system/src/main/res/drawable/ic_singing.xml new file mode 100644 index 00000000..f5cbe5a7 --- /dev/null +++ b/core/design-system/src/main/res/drawable/ic_singing.xml @@ -0,0 +1,326 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/feature/login/src/main/java/com/twix/login/LoginScreen.kt b/feature/login/src/main/java/com/twix/login/LoginScreen.kt index 30440179..bbca89cc 100644 --- a/feature/login/src/main/java/com/twix/login/LoginScreen.kt +++ b/feature/login/src/main/java/com/twix/login/LoginScreen.kt @@ -113,7 +113,7 @@ private fun LoginScreen(onClickLogin: (LoginType) -> Unit) { Box(modifier = Modifier.fillMaxSize()) { Image( - imageVector = ImageVector.vectorResource(R.drawable.ic_keepi_singing), + imageVector = ImageVector.vectorResource(R.drawable.ic_singing), contentDescription = null, modifier = Modifier From 8da390b0068f2d90c0eaa7ca4c6e96f331682b5a Mon Sep 17 00:00:00 2001 From: chanho0908 Date: Fri, 27 Feb 2026 11:39:09 +0900 Subject: [PATCH 13/25] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refactor:=20`Reactio?= =?UTF-8?q?nUiModel`=20=EB=A6=AC=EC=86=8C=EC=8A=A4=20=EB=84=A4=EC=9D=B4?= =?UTF-8?q?=EB=B0=8D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../detail/component/reaction/ReactionUiModel.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/feature/task-certification/src/main/java/com/twix/task_certification/detail/component/reaction/ReactionUiModel.kt b/feature/task-certification/src/main/java/com/twix/task_certification/detail/component/reaction/ReactionUiModel.kt index 6f68fd1a..2961c377 100644 --- a/feature/task-certification/src/main/java/com/twix/task_certification/detail/component/reaction/ReactionUiModel.kt +++ b/feature/task-certification/src/main/java/com/twix/task_certification/detail/component/reaction/ReactionUiModel.kt @@ -7,11 +7,11 @@ enum class ReactionUiModel( val type: GoalReactionType, val imageResources: Int, ) { - HAPPY(GoalReactionType.HAPPY, R.drawable.ic_keepi_happy), - TROUBLE(GoalReactionType.TROUBLE, R.drawable.ic_keepi_trouble), - LOVE(GoalReactionType.LOVE, R.drawable.ic_keepi_love), - DOUBT(GoalReactionType.DOUBT, R.drawable.ic_keepi_doubt), - FUCK(GoalReactionType.FUCK, R.drawable.ic_keepi_fuck), + HAPPY(GoalReactionType.HAPPY, R.drawable.ic_happy), + TROUBLE(GoalReactionType.TROUBLE, R.drawable.ic_trouble), + LOVE(GoalReactionType.LOVE, R.drawable.ic_love), + DOUBT(GoalReactionType.DOUBT, R.drawable.ic_doubt), + FUCK(GoalReactionType.FUCK, R.drawable.ic_fuck), ; companion object { From 6fab10232c049848bbbf309a00c1334364d5ad5c Mon Sep 17 00:00:00 2001 From: chanho0908 Date: Fri, 27 Feb 2026 11:55:14 +0900 Subject: [PATCH 14/25] =?UTF-8?q?=E2=9C=A8=20Feat:=20=EB=82=B4=20=EC=9D=B8?= =?UTF-8?q?=EC=A6=9D=EC=83=B7=20=EB=B0=98=EC=9D=91=20=ED=91=9C=EC=8B=9C=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EB=B0=8F=20=EB=B0=B0=EC=A7=80=20UI=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../res/drawable/ic_my_reaction_union.xml | 12 ++++ .../detail/TaskCertificationDetail.kt | 4 +- .../component/TaskCertificationCardContent.kt | 67 ++++++++++++++++++- .../TaskCertificationDetailUiState.kt | 3 +- 4 files changed, 79 insertions(+), 7 deletions(-) create mode 100644 core/design-system/src/main/res/drawable/ic_my_reaction_union.xml diff --git a/core/design-system/src/main/res/drawable/ic_my_reaction_union.xml b/core/design-system/src/main/res/drawable/ic_my_reaction_union.xml new file mode 100644 index 00000000..e2133fff --- /dev/null +++ b/core/design-system/src/main/res/drawable/ic_my_reaction_union.xml @@ -0,0 +1,12 @@ + + + + diff --git a/feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetail.kt b/feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetail.kt index 8aefc1e3..0e66194e 100644 --- a/feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetail.kt +++ b/feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetail.kt @@ -13,6 +13,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberUpdatedState +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity @@ -130,8 +131,7 @@ fun TaskCertificationDetailRoute( onPoke = { viewModel.dispatch(TaskCertificationDetailIntent.Poke) }, onSwipe = { viewModel.dispatch(TaskCertificationDetailIntent.SwipeCard) }, ) - - if (uiState.showMyPhotologReaction) { + if (!uiState.hasShownMyReaction) { val model = uiState.myReaction if (model != null) { ReactionEffect( diff --git a/feature/task-certification/src/main/java/com/twix/task_certification/detail/component/TaskCertificationCardContent.kt b/feature/task-certification/src/main/java/com/twix/task_certification/detail/component/TaskCertificationCardContent.kt index 1a59e509..dc1ac3b9 100644 --- a/feature/task-certification/src/main/java/com/twix/task_certification/detail/component/TaskCertificationCardContent.kt +++ b/feature/task-certification/src/main/java/com/twix/task_certification/detail/component/TaskCertificationCardContent.kt @@ -1,16 +1,26 @@ package com.twix.task_certification.detail.component +import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.padding 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.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.unit.dp import com.twix.designsystem.R import com.twix.designsystem.components.photolog.BackgroundCard import com.twix.designsystem.components.photolog.ForegroundCard +import com.twix.designsystem.theme.TwixTheme import com.twix.domain.model.enums.BetweenUs +import com.twix.task_certification.detail.component.reaction.ReactionUiModel import com.twix.task_certification.detail.component.swipe.SwipeableCard import com.twix.task_certification.detail.contract.TaskCertificationDetailUiState +import com.twix.task_certification.detail.preview.TaskCertificationDetailPreviewProvider @Composable internal fun TaskCertificationCardContent( @@ -19,7 +29,7 @@ internal fun TaskCertificationCardContent( onClickUpload: () -> Unit, onPoke: () -> Unit, ) { - Box(Modifier.fillMaxWidth()) { + Box { BackgroundCard( uploadedAt = uiState.displayedGoalUpdateAt, actionLabel = @@ -35,7 +45,6 @@ internal fun TaskCertificationCardContent( SwipeableCard( onSwipe = onSwipe, isDisplayingMyPhoto = uiState.isDisplayedMyPhotolog, - modifier = Modifier.fillMaxWidth(), ) { ForegroundCard( isCertificated = uiState.isDisplayedGoalCertificated, @@ -46,5 +55,57 @@ internal fun TaskCertificationCardContent( rotation = if (uiState.isDisplayedMyPhotolog) 0f else -8f, ) } + + MyReactionBadge( + visible = uiState.showMyPhotologReaction, + reaction = uiState.myReaction, + modifier = + Modifier + .align(Alignment.TopEnd) + .offset(x = (-8).dp, y = (-13).dp), + ) + } +} + +@Composable +private fun MyReactionBadge( + visible: Boolean, + reaction: ReactionUiModel?, + modifier: Modifier = Modifier, +) { + if (!visible) return + + reaction?.let { + Box(modifier = modifier) { + Image( + painter = painterResource(R.drawable.ic_my_reaction_union), + contentDescription = null, + ) + + Image( + painter = painterResource(it.imageResources), + contentDescription = null, + modifier = + Modifier + .padding(bottom = 10.dp) + .align(Alignment.Center), + ) + } + } +} + +@Preview(showBackground = true) +@Composable +private fun TaskCertificationCardContentPreview( + @PreviewParameter(TaskCertificationDetailPreviewProvider::class) + uiState: TaskCertificationDetailUiState, +) { + TwixTheme { + TaskCertificationCardContent( + uiState = uiState.copy(isLoading = true), + onSwipe = {}, + onClickUpload = {}, + onPoke = {}, + ) } } diff --git a/feature/task-certification/src/main/java/com/twix/task_certification/detail/contract/TaskCertificationDetailUiState.kt b/feature/task-certification/src/main/java/com/twix/task_certification/detail/contract/TaskCertificationDetailUiState.kt index 3fefb3a0..c7bbce2d 100644 --- a/feature/task-certification/src/main/java/com/twix/task_certification/detail/contract/TaskCertificationDetailUiState.kt +++ b/feature/task-certification/src/main/java/com/twix/task_certification/detail/contract/TaskCertificationDetailUiState.kt @@ -89,8 +89,7 @@ data class TaskCertificationDetailUiState( val showMyPhotologReaction: Boolean get() = - !hasShownMyReaction && - isDisplayedMyPhotolog && + isDisplayedMyPhotolog && myPhotolog?.reaction != null val myReaction: ReactionUiModel? From 14a99c3bfb9faafbb2a527a5345e4aaba89df20a Mon Sep 17 00:00:00 2001 From: chanho0908 Date: Fri, 27 Feb 2026 12:08:04 +0900 Subject: [PATCH 15/25] =?UTF-8?q?=E2=9C=A8=20Docs:=20`TaskCertificationDet?= =?UTF-8?q?ailUiState`=20KDoc=20=EC=A3=BC=EC=84=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TaskCertificationDetailUiState.kt | 83 ++++++++++++++++--- 1 file changed, 73 insertions(+), 10 deletions(-) diff --git a/feature/task-certification/src/main/java/com/twix/task_certification/detail/contract/TaskCertificationDetailUiState.kt b/feature/task-certification/src/main/java/com/twix/task_certification/detail/contract/TaskCertificationDetailUiState.kt index c7bbce2d..36fb382c 100644 --- a/feature/task-certification/src/main/java/com/twix/task_certification/detail/contract/TaskCertificationDetailUiState.kt +++ b/feature/task-certification/src/main/java/com/twix/task_certification/detail/contract/TaskCertificationDetailUiState.kt @@ -22,12 +22,21 @@ data class TaskCertificationDetailUiState( val myPhotolog: PhotologDetail? = null, val partnerPhotolog: PhotologDetail? = null, val isCompletedGoal: Boolean = false, + /** + * 내 인증샷에 상대방이 리액션을 남겼을 경우 최초 1회 인터렉션 렌더링을 위한 변수 + */ val hasShownMyReaction: Boolean = false, /** * 초기값으로 인해 찌르기/업로드 버튼이 렌더링 되는 것을 막기 위한 변수 - * */ + */ val isLoading: Boolean = false, ) : State { + /** + * 현재 [currentShow]에 해당하는 사용자의 포토로그 인증 여부 + * + * - [BetweenUs.ME]: 내 인증샷이 존재하면 `true` + * - [BetweenUs.PARTNER]: 파트너 인증샷이 존재하면 `true` + */ val isDisplayedGoalCertificated: Boolean get() = when (currentShow) { @@ -35,6 +44,12 @@ data class TaskCertificationDetailUiState( BetweenUs.PARTNER -> partnerPhotolog != null } + /** + * 현재 [currentShow]에 해당하는 포토로그의 업로드 시간을 상대적 시간 문자열 + * + * - [BetweenUs.ME]: 내 포토로그의 업로드 시간 + * - [BetweenUs.PARTNER]: 파트너 포토로그의 업로드 시간 + */ val displayedGoalUpdateAt: String get() = when (currentShow) { @@ -45,12 +60,17 @@ data class TaskCertificationDetailUiState( BetweenUs.PARTNER -> partnerPhotolog?.uploadedAt?.let { - RelativeTimeFormatter.format( - it, - ) + RelativeTimeFormatter.format(it) } ?: "" } + /** + * 현재 [currentShow]에 해당하는 인증샷 URL + * + * - [BetweenUs.ME]: 내 인증샷 이미지 URL + * - [BetweenUs.PARTNER]: 파트너 인증샷 이미지 URL + * + */ val displayedGoalImageUrl: String? get() = when (currentShow) { @@ -58,6 +78,13 @@ data class TaskCertificationDetailUiState( BetweenUs.PARTNER -> partnerPhotolog?.imageUrl } + /** + * 현재 [currentShow]에 해당하는 포토로그의 코멘트 + * + * - [BetweenUs.ME]: 내 코멘트 + * - [BetweenUs.PARTNER]: 파트너 코멘트 + * + */ val displayedGoalComment: String? get() = when (currentShow) { @@ -65,6 +92,12 @@ data class TaskCertificationDetailUiState( BetweenUs.PARTNER -> partnerPhotolog?.comment } + /** + * 현재 [currentShow]에 해당하는 사용자의 닉네임 + * + * - [BetweenUs.ME]: 내 닉네임 + * - [BetweenUs.PARTNER]: 파트너 닉네임 + */ val displayedNickname: String get() = when (currentShow) { @@ -72,26 +105,56 @@ data class TaskCertificationDetailUiState( BetweenUs.PARTNER -> partnerNickname } + /** + * 현재 화면이 내 인증샷을 표시하는 상태인지 여부 + * + * 내 인증샷일 때 `true` + */ val isDisplayedMyPhotolog: Boolean - get() = - currentShow == BetweenUs.ME + get() = currentShow == BetweenUs.ME + /** + * 내 포토로그를 수정할 수 있는지 여부 반환 + * + * 현재 내 포토로그를 보고 있고([isDisplayedMyPhotolog]), + * 인증이 완료된 상태([isDisplayedGoalCertificated])일 때 `true` + */ val canModify: Boolean - get() = - currentShow == BetweenUs.ME && isDisplayedGoalCertificated + get() = currentShow == BetweenUs.ME && isDisplayedGoalCertificated + /** + * 파트너 인증샷에 리액션을 남길 수 있는지 여부 + * + * 현재 파트너 인증샷을 보고 있고([BetweenUs.PARTNER]), + * 파트너의 인증이 완료된 상태([isDisplayedGoalCertificated])일 때 `true` + */ val canReaction: Boolean - get() = - currentShow == BetweenUs.PARTNER && isDisplayedGoalCertificated + get() = currentShow == BetweenUs.PARTNER && isDisplayedGoalCertificated + /** + * 인증샷 업로드 또는 찌르기 액션 버튼을 표시할지 여부를 반환 + * + * 목표가 완료되지 않았고([isCompletedGoal]이 `false`), + * 현재 대상의 인증이 없는 상태([isDisplayedGoalCertificated]가 `false`)일 때 `true` + */ val showActionButton: Boolean get() = !isCompletedGoal && !isDisplayedGoalCertificated + /** + * 내 포토로그에 달린 리액션 UI를 표시할지 여부를 반환 + * + * 내 포토로그를 보고 있고([isDisplayedMyPhotolog]), + * 리액션이 존재하며([myPhotolog]의 reaction이 non-null), + * 아직 한 번도 표시된 적 없을 때([hasShownMyReaction]이 `false`) `true`입니다. + */ val showMyPhotologReaction: Boolean get() = isDisplayedMyPhotolog && myPhotolog?.reaction != null + /** + * 내 포토로그의 리액션을 [ReactionUiModel]로 변환하여 반환 + */ val myReaction: ReactionUiModel? get() = myPhotolog?.reaction?.let { ReactionUiModel.find(it) } } From 62dcd1fd76d35eb755ad9873a1ec10a20705de12 Mon Sep 17 00:00:00 2001 From: chanho0908 Date: Fri, 27 Feb 2026 12:12:31 +0900 Subject: [PATCH 16/25] =?UTF-8?q?=E2=9C=A8=20Feat:=20=EB=82=B4=20=EC=9D=B8?= =?UTF-8?q?=EC=A6=9D=EC=83=B7=20=EB=85=B8=EC=B6=9C=20=EC=8B=9C=EC=97=90?= =?UTF-8?q?=EB=A7=8C=20=EB=A6=AC=EC=95=A1=EC=85=98=20=ED=9A=A8=EA=B3=BC?= =?UTF-8?q?=EA=B0=80=20=EB=82=98=ED=83=80=EB=82=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../twix/task_certification/detail/TaskCertificationDetail.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetail.kt b/feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetail.kt index 0e66194e..0be3b173 100644 --- a/feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetail.kt +++ b/feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetail.kt @@ -131,7 +131,7 @@ fun TaskCertificationDetailRoute( onPoke = { viewModel.dispatch(TaskCertificationDetailIntent.Poke) }, onSwipe = { viewModel.dispatch(TaskCertificationDetailIntent.SwipeCard) }, ) - if (!uiState.hasShownMyReaction) { + if (!uiState.hasShownMyReaction && uiState.isDisplayedMyPhotolog) { val model = uiState.myReaction if (model != null) { ReactionEffect( From 8ff18ab97712ce9995c257211a1b1fd34982a41f Mon Sep 17 00:00:00 2001 From: chanho0908 Date: Fri, 27 Feb 2026 12:13:43 +0900 Subject: [PATCH 17/25] =?UTF-8?q?=E2=9C=A8=20Feat:=20=EC=9D=B8=EC=A6=9D?= =?UTF-8?q?=EC=83=B7=20=EB=B0=98=EC=9D=91=20=EC=8B=9C=20=EB=AA=A9=ED=91=9C?= =?UTF-8?q?=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EA=B0=B1=EC=8B=A0=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../detail/TaskCertificationDetailViewModel.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetailViewModel.kt b/feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetailViewModel.kt index 79a6d614..d24a1e96 100644 --- a/feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetailViewModel.kt +++ b/feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetailViewModel.kt @@ -93,6 +93,7 @@ class TaskCertificationDetailViewModel( .debounce(DEBOUNCE_INTERVAL) .collectLatest { reaction -> reactToPhotolog(reaction) + goalRefreshBus.notifyGoalListChanged() } } } From 4c25f8f9363a446c02322539ca053f03c66c828f Mon Sep 17 00:00:00 2001 From: chanho0908 Date: Fri, 27 Feb 2026 12:15:36 +0900 Subject: [PATCH 18/25] =?UTF-8?q?=F0=9F=93=9D=20Docs:=20`TaskCertification?= =?UTF-8?q?DetailUiState`=20=EB=82=B4=20=EC=9A=A9=EC=96=B4=20=EC=A0=95?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TaskCertificationDetailUiState.kt | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/feature/task-certification/src/main/java/com/twix/task_certification/detail/contract/TaskCertificationDetailUiState.kt b/feature/task-certification/src/main/java/com/twix/task_certification/detail/contract/TaskCertificationDetailUiState.kt index 36fb382c..8002f3c4 100644 --- a/feature/task-certification/src/main/java/com/twix/task_certification/detail/contract/TaskCertificationDetailUiState.kt +++ b/feature/task-certification/src/main/java/com/twix/task_certification/detail/contract/TaskCertificationDetailUiState.kt @@ -32,7 +32,7 @@ data class TaskCertificationDetailUiState( val isLoading: Boolean = false, ) : State { /** - * 현재 [currentShow]에 해당하는 사용자의 포토로그 인증 여부 + * 현재 [currentShow]에 해당하는 사용자의 인증샷 인증 여부 * * - [BetweenUs.ME]: 내 인증샷이 존재하면 `true` * - [BetweenUs.PARTNER]: 파트너 인증샷이 존재하면 `true` @@ -45,10 +45,10 @@ data class TaskCertificationDetailUiState( } /** - * 현재 [currentShow]에 해당하는 포토로그의 업로드 시간을 상대적 시간 문자열 + * 현재 [currentShow]에 해당하는 인증샷의 업로드 시간을 상대적 시간 문자열 * - * - [BetweenUs.ME]: 내 포토로그의 업로드 시간 - * - [BetweenUs.PARTNER]: 파트너 포토로그의 업로드 시간 + * - [BetweenUs.ME]: 내 인증샷 업로드 시간 + * - [BetweenUs.PARTNER]: 파트너 인증샷 업로드 시간 */ val displayedGoalUpdateAt: String get() = @@ -79,7 +79,7 @@ data class TaskCertificationDetailUiState( } /** - * 현재 [currentShow]에 해당하는 포토로그의 코멘트 + * 현재 [currentShow]에 해당하는 인증샷의 코멘트 * * - [BetweenUs.ME]: 내 코멘트 * - [BetweenUs.PARTNER]: 파트너 코멘트 @@ -114,9 +114,9 @@ data class TaskCertificationDetailUiState( get() = currentShow == BetweenUs.ME /** - * 내 포토로그를 수정할 수 있는지 여부 반환 + * 내 인증샷를 수정할 수 있는지 여부 반환 * - * 현재 내 포토로그를 보고 있고([isDisplayedMyPhotolog]), + * 현재 내 인증샷를 보고 있고([isDisplayedMyPhotolog]), * 인증이 완료된 상태([isDisplayedGoalCertificated])일 때 `true` */ val canModify: Boolean @@ -141,11 +141,11 @@ data class TaskCertificationDetailUiState( get() = !isCompletedGoal && !isDisplayedGoalCertificated /** - * 내 포토로그에 달린 리액션 UI를 표시할지 여부를 반환 + * 내 인증샷에 달린 리액션 UI를 표시할지 여부를 반환 * - * 내 포토로그를 보고 있고([isDisplayedMyPhotolog]), + * 내 인증샷을 보고 있고([isDisplayedMyPhotolog]), * 리액션이 존재하며([myPhotolog]의 reaction이 non-null), - * 아직 한 번도 표시된 적 없을 때([hasShownMyReaction]이 `false`) `true`입니다. + * 아직 한 번도 표시된 적 없을 때([hasShownMyReaction]이 `false`) `true` */ val showMyPhotologReaction: Boolean get() = @@ -153,7 +153,7 @@ data class TaskCertificationDetailUiState( myPhotolog?.reaction != null /** - * 내 포토로그의 리액션을 [ReactionUiModel]로 변환하여 반환 + * 내 인증샷의 리액션을 [ReactionUiModel]로 변환하여 반환 */ val myReaction: ReactionUiModel? get() = myPhotolog?.reaction?.let { ReactionUiModel.find(it) } From 063fc40f0f468e33ff2cee1fbb168936414f1893 Mon Sep 17 00:00:00 2001 From: chanho0908 Date: Fri, 27 Feb 2026 12:24:58 +0900 Subject: [PATCH 19/25] =?UTF-8?q?=E2=9C=A8=20Feat:=20=EB=82=B4=20=EC=9D=B8?= =?UTF-8?q?=EC=A6=9D=EC=83=B7=20=EB=A6=AC=EC=95=A1=EC=85=98=20=EB=B1=83?= =?UTF-8?q?=EC=A7=80=20=ED=91=9C=EC=8B=9C=20=EB=A1=9C=EC=A7=81=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20=EB=B0=8F=20=EB=B3=80=EC=88=98=EB=AA=85=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../detail/component/TaskCertificationCardContent.kt | 2 +- .../detail/contract/TaskCertificationDetailUiState.kt | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/feature/task-certification/src/main/java/com/twix/task_certification/detail/component/TaskCertificationCardContent.kt b/feature/task-certification/src/main/java/com/twix/task_certification/detail/component/TaskCertificationCardContent.kt index dc1ac3b9..0f865749 100644 --- a/feature/task-certification/src/main/java/com/twix/task_certification/detail/component/TaskCertificationCardContent.kt +++ b/feature/task-certification/src/main/java/com/twix/task_certification/detail/component/TaskCertificationCardContent.kt @@ -57,7 +57,7 @@ internal fun TaskCertificationCardContent( } MyReactionBadge( - visible = uiState.showMyPhotologReaction, + visible = uiState.showMyPhotologReactionBadge, reaction = uiState.myReaction, modifier = Modifier diff --git a/feature/task-certification/src/main/java/com/twix/task_certification/detail/contract/TaskCertificationDetailUiState.kt b/feature/task-certification/src/main/java/com/twix/task_certification/detail/contract/TaskCertificationDetailUiState.kt index 8002f3c4..f5d70449 100644 --- a/feature/task-certification/src/main/java/com/twix/task_certification/detail/contract/TaskCertificationDetailUiState.kt +++ b/feature/task-certification/src/main/java/com/twix/task_certification/detail/contract/TaskCertificationDetailUiState.kt @@ -141,13 +141,12 @@ data class TaskCertificationDetailUiState( get() = !isCompletedGoal && !isDisplayedGoalCertificated /** - * 내 인증샷에 달린 리액션 UI를 표시할지 여부를 반환 + * 내 인증샷에 달린 리액션 뱃지를 표시할지 여부를 반환 * * 내 인증샷을 보고 있고([isDisplayedMyPhotolog]), - * 리액션이 존재하며([myPhotolog]의 reaction이 non-null), - * 아직 한 번도 표시된 적 없을 때([hasShownMyReaction]이 `false`) `true` + * 리액션이 존재하며([myPhotolog]의 reaction이 non-null) 일 때 `true` */ - val showMyPhotologReaction: Boolean + val showMyPhotologReactionBadge: Boolean get() = isDisplayedMyPhotolog && myPhotolog?.reaction != null From 951177227479d9bd0ae5b59b3d0190a20d1b87c1 Mon Sep 17 00:00:00 2001 From: chanho0908 Date: Fri, 27 Feb 2026 12:38:10 +0900 Subject: [PATCH 20/25] =?UTF-8?q?=E2=9C=A8=20Feat:=20=EB=A6=AC=EC=95=A1?= =?UTF-8?q?=EC=85=98=20=ED=9A=A8=EA=B3=BC=20=EC=88=98=EC=B9=98=20=EC=A1=B0?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../twix/task_certification/detail/TaskCertificationDetail.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetail.kt b/feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetail.kt index 0be3b173..07770dc7 100644 --- a/feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetail.kt +++ b/feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetail.kt @@ -13,7 +13,6 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberUpdatedState -import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity @@ -139,6 +138,8 @@ fun TaskCertificationDetailRoute( spec = ReactionEffectSpec( particleCount = 10, + durationRange = 500..800, + // 전체 화면 높이까지 퍼짐 travelDistanceRange = 500..screenHeightPx.toInt(), ), onFinished = { From b7cb02d4f75337e6504254970997bc49d0f34fac Mon Sep 17 00:00:00 2001 From: chanho0908 Date: Fri, 27 Feb 2026 14:29:43 +0900 Subject: [PATCH 21/25] =?UTF-8?q?=F0=9F=8E=A8=20Style:=20=EB=A6=AC?= =?UTF-8?q?=EC=95=A1=EC=85=98=20=EC=95=84=EC=9D=B4=EC=BD=98=20=EB=A6=AC?= =?UTF-8?q?=EC=86=8C=EC=8A=A4=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/res/drawable/ic_doubt.xml | 136 ++++------ .../src/main/res/drawable/ic_fuck.xml | 84 +++--- .../src/main/res/drawable/ic_happy.xml | 89 +++--- .../src/main/res/drawable/ic_love.xml | 89 +++--- .../src/main/res/drawable/ic_trouble.xml | 253 ++++++++++-------- 5 files changed, 342 insertions(+), 309 deletions(-) diff --git a/core/design-system/src/main/res/drawable/ic_doubt.xml b/core/design-system/src/main/res/drawable/ic_doubt.xml index bdf5ab45..ddbb2b7a 100644 --- a/core/design-system/src/main/res/drawable/ic_doubt.xml +++ b/core/design-system/src/main/res/drawable/ic_doubt.xml @@ -1,85 +1,67 @@ + android:width="52dp" + android:height="52dp" + android:viewportWidth="52" + android:viewportHeight="52"> + - + - - - - - - - - - - - - - - - + + + + + + + + + diff --git a/core/design-system/src/main/res/drawable/ic_fuck.xml b/core/design-system/src/main/res/drawable/ic_fuck.xml index 97799f48..995c2f67 100644 --- a/core/design-system/src/main/res/drawable/ic_fuck.xml +++ b/core/design-system/src/main/res/drawable/ic_fuck.xml @@ -1,135 +1,135 @@ + android:width="52dp" + android:height="52dp" + android:viewportWidth="52" + android:viewportHeight="52"> + android:pathData="M3.043,3.047h46v46h-46z"/> diff --git a/core/design-system/src/main/res/drawable/ic_happy.xml b/core/design-system/src/main/res/drawable/ic_happy.xml index a15aeaf2..a0ae82a2 100644 --- a/core/design-system/src/main/res/drawable/ic_happy.xml +++ b/core/design-system/src/main/res/drawable/ic_happy.xml @@ -1,87 +1,102 @@ + android:width="52dp" + android:height="52dp" + android:viewportWidth="52" + android:viewportHeight="52"> + android:pathData="M1.93,4.719h49v44h-49z"/> + android:pathData="M16.897,35.942C18.989,34.838 19.789,32.248 18.685,30.157C17.582,28.065 14.991,27.265 12.9,28.368C10.809,29.472 10.008,32.063 11.112,34.154C12.216,36.245 14.806,37.046 16.897,35.942Z" + android:fillColor="#FDE0DF"/> + android:pathData="M38.389,28.387C40.481,27.284 41.281,24.693 40.178,22.602C39.074,20.511 36.484,19.71 34.392,20.814C32.301,21.918 31.5,24.508 32.604,26.599C33.708,28.691 36.298,29.491 38.389,28.387Z" + android:fillColor="#FDE0DF"/> - + android:pathData="M39.641,16.583C39.641,16.583 40.623,12.381 44.924,13.397C49.225,14.412 50.034,22.535 43.265,23.493" + android:fillColor="#ffffff"/> + android:pathData="M19.366,23.199C19.117,23.046 18.916,22.884 18.723,22.779C18.465,22.638 18.248,22.546 18.052,22.45C17.826,22.34 17.611,22.238 17.379,22.131C17.183,22.035 16.951,21.973 16.705,21.826C16.512,21.721 16.309,21.568 16.063,21.406" + android:strokeLineJoin="round" + android:strokeWidth="1.38" + android:fillColor="#00000000" + android:strokeColor="#181818" + android:strokeLineCap="round"/> + + diff --git a/core/design-system/src/main/res/drawable/ic_love.xml b/core/design-system/src/main/res/drawable/ic_love.xml index 476ecc69..45b98ba7 100644 --- a/core/design-system/src/main/res/drawable/ic_love.xml +++ b/core/design-system/src/main/res/drawable/ic_love.xml @@ -1,84 +1,101 @@ + android:width="52dp" + android:height="52dp" + android:viewportWidth="52" + android:viewportHeight="52"> + android:pathData="M4.711,2.648h42v47h-42z"/> + android:pathData="M16.956,31.1C19.032,30.004 19.827,27.433 18.731,25.357C17.636,23.282 15.065,22.487 12.989,23.583C10.913,24.678 10.119,27.249 11.214,29.325C12.31,31.401 14.881,32.195 16.956,31.1Z" + android:fillColor="#FDE0DF"/> + android:pathData="M38.277,30.084C40.353,28.988 41.147,26.418 40.051,24.342C38.956,22.266 36.385,21.472 34.309,22.567C32.234,23.663 31.439,26.233 32.535,28.309C33.63,30.385 36.201,31.18 38.277,30.084Z" + android:fillColor="#FDE0DF"/> - + + android:pathData="M22.942,28.705L22.582,29.552L23.118,31.977L24.468,30.666L26.581,30.549L28.076,30.069L30.025,30.9L29.773,28.305L27.603,28.172L25.887,27.879L24.279,28.769L22.942,28.71V28.705Z" + android:fillColor="#BC6159"/> + + + diff --git a/core/design-system/src/main/res/drawable/ic_trouble.xml b/core/design-system/src/main/res/drawable/ic_trouble.xml index 35894ac5..37a013a9 100644 --- a/core/design-system/src/main/res/drawable/ic_trouble.xml +++ b/core/design-system/src/main/res/drawable/ic_trouble.xml @@ -1,125 +1,144 @@ + android:width="52dp" + android:height="52dp" + android:viewportWidth="52" + android:viewportHeight="52"> + - + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + From 938031c597bc30fc4cea8f1060a9446554606a0e Mon Sep 17 00:00:00 2001 From: chanho0908 Date: Fri, 27 Feb 2026 14:54:45 +0900 Subject: [PATCH 22/25] =?UTF-8?q?=E2=9C=A8=20Style:=20`ic=5Fhug`=20?= =?UTF-8?q?=EC=95=84=EC=9D=B4=EC=BD=98=20=EB=A6=AC=EC=86=8C=EC=8A=A4=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/res/drawable/ic_hug.xml | 138 ++++++++++++------ 1 file changed, 91 insertions(+), 47 deletions(-) diff --git a/core/design-system/src/main/res/drawable/ic_hug.xml b/core/design-system/src/main/res/drawable/ic_hug.xml index 809bfcf6..ef18da7b 100644 --- a/core/design-system/src/main/res/drawable/ic_hug.xml +++ b/core/design-system/src/main/res/drawable/ic_hug.xml @@ -4,120 +4,164 @@ android:viewportWidth="86" android:viewportHeight="64"> + android:pathData="M43.036,31.865C43.235,29.792 41.563,27.934 39.301,27.715C37.039,27.497 35.044,29 34.845,31.074C34.646,33.147 36.318,35.005 38.58,35.224C40.842,35.442 42.837,33.938 43.036,31.865Z" + android:fillColor="#FDE0DF"/> + android:pathData="M16.676,34.327C19.068,34.223 20.929,32.317 20.834,30.069C20.738,27.822 18.722,26.084 16.33,26.187C13.939,26.291 12.078,28.197 12.173,30.445C12.269,32.693 14.285,34.431 16.676,34.327Z" + android:fillColor="#FDE0DF"/> + + + android:pathData="M49.833,29.949C50.066,28.005 48.667,26.238 46.707,26.002C44.747,25.766 42.969,27.15 42.736,29.094C42.502,31.038 43.901,32.805 45.861,33.041C47.821,33.277 49.599,31.893 49.833,29.949Z" + android:fillColor="#FDE0DF"/> + android:pathData="M68.709,36.657C69.242,34.526 67.865,32.344 65.634,31.783C63.402,31.221 61.161,32.493 60.629,34.623C60.096,36.754 61.473,38.936 63.704,39.497C65.936,40.059 68.176,38.787 68.709,36.657Z" + android:fillColor="#FDE0DF"/> + - - - - - - - - + + + + + + + Date: Fri, 27 Feb 2026 16:08:40 +0900 Subject: [PATCH 23/25] =?UTF-8?q?Revert=20"=E2=9C=A8=20Style:=20`ic=5Fhug`?= =?UTF-8?q?=20=EC=95=84=EC=9D=B4=EC=BD=98=20=EB=A6=AC=EC=86=8C=EC=8A=A4=20?= =?UTF-8?q?=EC=88=98=EC=A0=95"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 938031c597bc30fc4cea8f1060a9446554606a0e. --- .../src/main/res/drawable/ic_hug.xml | 138 ++++++------------ 1 file changed, 47 insertions(+), 91 deletions(-) diff --git a/core/design-system/src/main/res/drawable/ic_hug.xml b/core/design-system/src/main/res/drawable/ic_hug.xml index ef18da7b..809bfcf6 100644 --- a/core/design-system/src/main/res/drawable/ic_hug.xml +++ b/core/design-system/src/main/res/drawable/ic_hug.xml @@ -4,164 +4,120 @@ android:viewportWidth="86" android:viewportHeight="64"> + android:pathData="M41.49,30.346C41.65,28.534 40.163,26.924 38.17,26.75C36.177,26.576 34.432,27.905 34.273,29.718C34.114,31.531 35.6,33.141 37.593,33.314C39.586,33.488 41.331,32.159 41.49,30.346Z" + android:fillColor="#FFD5DE"/> + android:pathData="M21.775,33.16C24.262,33.032 26.203,31.454 26.109,29.637C26.015,27.82 23.922,26.451 21.434,26.58C18.947,26.708 17.006,28.286 17.1,30.103C17.194,31.92 19.287,33.289 21.775,33.16Z" + android:fillColor="#FFD5DE"/> - - + android:pathData="M50.867,30.564C50.984,28.748 49.433,27.171 47.404,27.042C45.374,26.912 43.634,28.279 43.517,30.095C43.4,31.911 44.95,33.488 46.979,33.617C49.009,33.747 50.749,32.38 50.867,30.564Z" + android:fillColor="#FFD5DE"/> + android:pathData="M68.137,33.378C68.482,31.591 66.744,29.756 64.256,29.279C61.767,28.802 59.47,29.864 59.125,31.651C58.78,33.438 60.517,35.273 63.006,35.75C65.494,36.227 67.791,35.165 68.137,33.378Z" + android:fillColor="#FFD5DE"/> - - - - - - - - - + + + + + + + Date: Fri, 27 Feb 2026 16:08:47 +0900 Subject: [PATCH 24/25] =?UTF-8?q?Revert=20"=F0=9F=8E=A8=20Style:=20?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=ED=99=94=EB=A9=B4=20=EC=95=84?= =?UTF-8?q?=EC=9D=B4=EC=BD=98=20=EB=A6=AC=EC=86=8C=EC=8A=A4=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 3e4896ad815ee3ab4f9e263ea6be4379494abe10. --- .../src/main/res/drawable/ic_singing.xml | 326 ------------------ .../main/java/com/twix/login/LoginScreen.kt | 2 +- 2 files changed, 1 insertion(+), 327 deletions(-) delete mode 100644 core/design-system/src/main/res/drawable/ic_singing.xml diff --git a/core/design-system/src/main/res/drawable/ic_singing.xml b/core/design-system/src/main/res/drawable/ic_singing.xml deleted file mode 100644 index f5cbe5a7..00000000 --- a/core/design-system/src/main/res/drawable/ic_singing.xml +++ /dev/null @@ -1,326 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/feature/login/src/main/java/com/twix/login/LoginScreen.kt b/feature/login/src/main/java/com/twix/login/LoginScreen.kt index bbca89cc..30440179 100644 --- a/feature/login/src/main/java/com/twix/login/LoginScreen.kt +++ b/feature/login/src/main/java/com/twix/login/LoginScreen.kt @@ -113,7 +113,7 @@ private fun LoginScreen(onClickLogin: (LoginType) -> Unit) { Box(modifier = Modifier.fillMaxSize()) { Image( - imageVector = ImageVector.vectorResource(R.drawable.ic_singing), + imageVector = ImageVector.vectorResource(R.drawable.ic_keepi_singing), contentDescription = null, modifier = Modifier From 2a1e6af7e84f6fbd7794e7bbe1fdc30bdb54b6c2 Mon Sep 17 00:00:00 2001 From: chanho0908 Date: Fri, 27 Feb 2026 16:08:47 +0900 Subject: [PATCH 25/25] =?UTF-8?q?Revert=20"=F0=9F=8E=A8=20Style:=20?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=ED=99=94=EB=A9=B4=20=EC=95=84?= =?UTF-8?q?=EC=9D=B4=EC=BD=98=20=EB=A6=AC=EC=86=8C=EC=8A=A4=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 3e4896ad815ee3ab4f9e263ea6be4379494abe10. --- .../main/res/drawable/ic_keepi_singing.xml | 242 ++++++++++++++++++ 1 file changed, 242 insertions(+) create mode 100644 core/design-system/src/main/res/drawable/ic_keepi_singing.xml diff --git a/core/design-system/src/main/res/drawable/ic_keepi_singing.xml b/core/design-system/src/main/res/drawable/ic_keepi_singing.xml new file mode 100644 index 00000000..b2a6ae27 --- /dev/null +++ b/core/design-system/src/main/res/drawable/ic_keepi_singing.xml @@ -0,0 +1,242 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +