From 17bb2680bd8b1270798a78678ca4363c5cbd0f7e Mon Sep 17 00:00:00 2001 From: SeonJeongk Date: Sat, 1 Feb 2025 15:58:49 +0900 Subject: [PATCH 01/11] =?UTF-8?q?[TNT-189]=20refactor:=20TnTSwitch=20onCli?= =?UTF-8?q?ck=EC=9C=BC=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/co/kr/tnt/designsystem/component/Toggle.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/designsystem/src/main/java/co/kr/tnt/designsystem/component/Toggle.kt b/core/designsystem/src/main/java/co/kr/tnt/designsystem/component/Toggle.kt index a3c15c9f..71e7ba1f 100644 --- a/core/designsystem/src/main/java/co/kr/tnt/designsystem/component/Toggle.kt +++ b/core/designsystem/src/main/java/co/kr/tnt/designsystem/component/Toggle.kt @@ -54,7 +54,7 @@ fun TnTCheckToggle( @Composable fun TnTSwitch( checked: Boolean, - onCheckedChange: () -> Unit, + onClick: () -> Unit, modifier: Modifier = Modifier, ) { val trackColor = if (checked) { @@ -75,7 +75,7 @@ fun TnTSwitch( .height(24.dp) .clip(RoundedCornerShape(12.dp)) .background(trackColor) - .clickable(onClick = onCheckedChange) + .clickable(onClick = onClick) .padding(horizontal = 2.dp), ) { Box( @@ -109,7 +109,7 @@ private fun TnTSwitchPreview() { TnTSwitch( checked = checked, - onCheckedChange = { checked = !checked }, + onClick = { checked = !checked }, ) } } From 171679331703c8e7bfa12793b34724dc4e53f682 Mon Sep 17 00:00:00 2001 From: SeonJeongk Date: Sat, 1 Feb 2025 16:51:20 +0900 Subject: [PATCH 02/11] =?UTF-8?q?[TNT-189]=20feat:=20Notification=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../component/notification/Notification.kt | 88 +++++++++++++++++++ .../notification/model/NotificationType.kt | 8 ++ .../src/main/res/drawable/ic_link_notif.xml | 25 ++++++ .../main/res/drawable/ic_schedule_notif.xml | 33 +++++++ 4 files changed, 154 insertions(+) create mode 100644 core/designsystem/src/main/java/co/kr/tnt/designsystem/component/notification/Notification.kt create mode 100644 core/designsystem/src/main/java/co/kr/tnt/designsystem/component/notification/model/NotificationType.kt create mode 100644 core/designsystem/src/main/res/drawable/ic_link_notif.xml create mode 100644 core/designsystem/src/main/res/drawable/ic_schedule_notif.xml diff --git a/core/designsystem/src/main/java/co/kr/tnt/designsystem/component/notification/Notification.kt b/core/designsystem/src/main/java/co/kr/tnt/designsystem/component/notification/Notification.kt new file mode 100644 index 00000000..0e6cd668 --- /dev/null +++ b/core/designsystem/src/main/java/co/kr/tnt/designsystem/component/notification/Notification.kt @@ -0,0 +1,88 @@ +package co.kr.tnt.designsystem.component.notification + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import co.kr.tnt.designsystem.component.notification.model.NotificationType +import co.kr.tnt.designsystem.theme.TnTTheme + +@Composable +fun TnTNotification( + type: NotificationType, + title: String, + contents: String, + time: String, + isChecked: Boolean, +) { + val backgroundColor = if (isChecked) { + TnTTheme.colors.commonColors.Common0 + } else { + TnTTheme.colors.neutralColors.Neutral100 + } + + Row( + horizontalArrangement = Arrangement.spacedBy(16.dp), + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .fillMaxWidth() + .background(backgroundColor) + .padding(20.dp), + ) { + Image( + painter = painterResource(type.icon), + contentDescription = null, + ) + Column( + modifier = Modifier.fillMaxWidth(), + ) { + Row( + horizontalArrangement = Arrangement.SpaceBetween, + modifier = Modifier + .fillMaxWidth() + .padding(bottom = 6.dp), + ) { + Text( + text = title, + color = TnTTheme.colors.neutralColors.Neutral400, + style = TnTTheme.typography.label1Bold, + ) + Text( + text = time, + color = TnTTheme.colors.neutralColors.Neutral400, + style = TnTTheme.typography.label1Medium, + ) + } + Text( + text = contents, + color = TnTTheme.colors.neutralColors.Neutral900, + style = TnTTheme.typography.body2Medium, + modifier = Modifier.fillMaxWidth(), + ) + } + } +} + +@Preview +@Composable +private fun TnTNotificationPreview() { + TnTTheme { + TnTNotification( + type = NotificationType.LINK, + title = "알림 문구", + contents = "알림 상세 문구", + time = "2분전", + isChecked = false, + ) + } +} diff --git a/core/designsystem/src/main/java/co/kr/tnt/designsystem/component/notification/model/NotificationType.kt b/core/designsystem/src/main/java/co/kr/tnt/designsystem/component/notification/model/NotificationType.kt new file mode 100644 index 00000000..521f0f05 --- /dev/null +++ b/core/designsystem/src/main/java/co/kr/tnt/designsystem/component/notification/model/NotificationType.kt @@ -0,0 +1,8 @@ +package co.kr.tnt.designsystem.component.notification.model + +import co.kr.tnt.core.designsystem.R + +enum class NotificationType(val icon: Int) { + LINK(R.drawable.ic_link_notif), + SCHEDULE(R.drawable.ic_schedule_notif), +} diff --git a/core/designsystem/src/main/res/drawable/ic_link_notif.xml b/core/designsystem/src/main/res/drawable/ic_link_notif.xml new file mode 100644 index 00000000..4dc2c318 --- /dev/null +++ b/core/designsystem/src/main/res/drawable/ic_link_notif.xml @@ -0,0 +1,25 @@ + + + + + + + diff --git a/core/designsystem/src/main/res/drawable/ic_schedule_notif.xml b/core/designsystem/src/main/res/drawable/ic_schedule_notif.xml new file mode 100644 index 00000000..b2baad87 --- /dev/null +++ b/core/designsystem/src/main/res/drawable/ic_schedule_notif.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + From f0b90f4cfedb13bff8adcd8bd2e4f04b6a47892d Mon Sep 17 00:00:00 2001 From: SeonJeongk Date: Sun, 2 Feb 2025 01:26:20 +0900 Subject: [PATCH 03/11] =?UTF-8?q?[TNT-189]=20fix:=20TnTSwitch=20onClick=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/co/kr/tnt/trainee/mypage/TraineeMyPageScreen.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feature/trainee/mypage/src/main/java/co/kr/tnt/trainee/mypage/TraineeMyPageScreen.kt b/feature/trainee/mypage/src/main/java/co/kr/tnt/trainee/mypage/TraineeMyPageScreen.kt index ff783ed1..595467ea 100644 --- a/feature/trainee/mypage/src/main/java/co/kr/tnt/trainee/mypage/TraineeMyPageScreen.kt +++ b/feature/trainee/mypage/src/main/java/co/kr/tnt/trainee/mypage/TraineeMyPageScreen.kt @@ -159,7 +159,7 @@ private fun TraineeMyPageScreen( ) TnTSwitch( checked = state.isPushEnabled, - onCheckedChange = onPushNotificationToggle, + onClick = onPushNotificationToggle, ) } Column( From 92fd0e473934d54ed1d498949b06abdd2042a043 Mon Sep 17 00:00:00 2001 From: SeonJeongk Date: Sun, 2 Feb 2025 02:27:44 +0900 Subject: [PATCH 04/11] =?UTF-8?q?[TNT-189]=20chore:=20trainee:notification?= =?UTF-8?q?=20=EB=AA=A8=EB=93=88=20=EC=B5=9C=EC=B4=88=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/co/kr/tnt/navigation/RouteModel.kt | 3 + core/ui/src/main/res/values/strings.xml | 2 + feature/main/build.gradle.kts | 1 + .../main/java/co/kr/tnt/main/ui/TnTNavHost.kt | 4 ++ feature/trainee/notification/.gitignore | 1 + feature/trainee/notification/build.gradle.kts | 13 +++++ .../notification/src/main/AndroidManifest.xml | 4 ++ .../notification/TraineeNotificationScreen.kt | 56 +++++++++++++++++++ .../TraineeNotificationViewModel.kt | 8 +++ .../TraineeNotificationNavigation.kt | 25 +++++++++ settings.gradle.kts | 1 + 11 files changed, 118 insertions(+) create mode 100644 feature/trainee/notification/.gitignore create mode 100644 feature/trainee/notification/build.gradle.kts create mode 100644 feature/trainee/notification/src/main/AndroidManifest.xml create mode 100644 feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/TraineeNotificationScreen.kt create mode 100644 feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/TraineeNotificationViewModel.kt create mode 100644 feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/navigation/TraineeNotificationNavigation.kt diff --git a/core/navigation/src/main/java/co/kr/tnt/navigation/RouteModel.kt b/core/navigation/src/main/java/co/kr/tnt/navigation/RouteModel.kt index 7e6abc96..da9e6027 100644 --- a/core/navigation/src/main/java/co/kr/tnt/navigation/RouteModel.kt +++ b/core/navigation/src/main/java/co/kr/tnt/navigation/RouteModel.kt @@ -42,6 +42,9 @@ sealed interface Route { @Serializable data object TraineeMyPage : Route + @Serializable + data object TraineeNotification : Route + @Serializable data class WebView(val url: String) : Route } diff --git a/core/ui/src/main/res/values/strings.xml b/core/ui/src/main/res/values/strings.xml index edc0d4ac..87b2e5bb 100644 --- a/core/ui/src/main/res/values/strings.xml +++ b/core/ui/src/main/res/values/strings.xml @@ -35,6 +35,8 @@ cm kg + 알림 + 아침 점심 diff --git a/feature/main/build.gradle.kts b/feature/main/build.gradle.kts index a89ffbe9..7ae5c618 100644 --- a/feature/main/build.gradle.kts +++ b/feature/main/build.gradle.kts @@ -18,6 +18,7 @@ dependencies { implementation(projects.feature.trainer.connect) implementation(projects.feature.trainee.connect) implementation(projects.feature.trainee.mypage) + implementation(projects.feature.trainee.notification) implementation(libs.androidx.core.ktx) implementation(libs.androidx.appcompat) diff --git a/feature/main/src/main/java/co/kr/tnt/main/ui/TnTNavHost.kt b/feature/main/src/main/java/co/kr/tnt/main/ui/TnTNavHost.kt index cbb86b62..49de7794 100644 --- a/feature/main/src/main/java/co/kr/tnt/main/ui/TnTNavHost.kt +++ b/feature/main/src/main/java/co/kr/tnt/main/ui/TnTNavHost.kt @@ -17,6 +17,7 @@ import co.kr.tnt.roleselect.roleSelectionScreen import co.kr.tnt.trainee.connect.navigation.navigateToTraineeConnect import co.kr.tnt.trainee.connect.navigation.traineeConnectScreen import co.kr.tnt.trainee.mypage.navigation.traineeMyPageScreen +import co.kr.tnt.trainee.notification.navigation.traineeNotification import co.kr.tnt.trainee.signup.navigation.navigateToTraineeSignUp import co.kr.tnt.trainee.signup.navigation.traineeSignUpScreen import co.kr.tnt.trainer.connect.navigation.navigateToTrainerConnect @@ -100,6 +101,9 @@ fun TnTNavHost( navController.navigateToWebView(url = url) }, ) + traineeNotification( + navigateToPrevious = { navController.popBackStack() }, + ) webViewScreen( navigateToPrevious = { navController.popBackStack() }, ) diff --git a/feature/trainee/notification/.gitignore b/feature/trainee/notification/.gitignore new file mode 100644 index 00000000..42afabfd --- /dev/null +++ b/feature/trainee/notification/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/feature/trainee/notification/build.gradle.kts b/feature/trainee/notification/build.gradle.kts new file mode 100644 index 00000000..095303af --- /dev/null +++ b/feature/trainee/notification/build.gradle.kts @@ -0,0 +1,13 @@ +import co.kr.tnt.setNamespace + +plugins { + id("tnt.android.feature") +} + +android { + setNamespace("feature.notification") +} + +dependencies { + implementation(libs.kotlinx.immutable) +} diff --git a/feature/trainee/notification/src/main/AndroidManifest.xml b/feature/trainee/notification/src/main/AndroidManifest.xml new file mode 100644 index 00000000..8bdb7e14 --- /dev/null +++ b/feature/trainee/notification/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + diff --git a/feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/TraineeNotificationScreen.kt b/feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/TraineeNotificationScreen.kt new file mode 100644 index 00000000..33a8c4dc --- /dev/null +++ b/feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/TraineeNotificationScreen.kt @@ -0,0 +1,56 @@ +package co.kr.tnt.trainee.notification + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import co.kr.tnt.designsystem.component.TnTTopBarWithBackButton +import co.kr.tnt.designsystem.theme.TnTTheme +import co.kr.tnt.core.ui.R as uiResource + +@Composable +internal fun TraineeNotificationRoute( + navigateToPrevious: () -> Unit, +) { + TraineeNotificationScreen( + navigateToPrevious = navigateToPrevious, + ) +} + +@Composable +fun TraineeNotificationScreen( + navigateToPrevious: () -> Unit, +) { + Scaffold( + topBar = { + TnTTopBarWithBackButton( + title = stringResource(uiResource.string.notification), + onBackClick = navigateToPrevious, + ) + }, + contentColor = TnTTheme.colors.commonColors.Common0, + ) { innerPadding -> + Column( + modifier = Modifier + .fillMaxSize() + .padding(innerPadding), + ) { + Text(text = "text") + } + } +} + +@Preview +@Composable +private fun TraineeNotificationScreenPreview() { + TnTTheme { + TraineeNotificationScreen( + navigateToPrevious = {}, + ) + } +} diff --git a/feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/TraineeNotificationViewModel.kt b/feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/TraineeNotificationViewModel.kt new file mode 100644 index 00000000..efeeddee --- /dev/null +++ b/feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/TraineeNotificationViewModel.kt @@ -0,0 +1,8 @@ +package co.kr.tnt.trainee.notification + +import androidx.lifecycle.ViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject + +@HiltViewModel +internal class TraineeNotificationViewModel @Inject constructor() : ViewModel() diff --git a/feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/navigation/TraineeNotificationNavigation.kt b/feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/navigation/TraineeNotificationNavigation.kt new file mode 100644 index 00000000..6730939a --- /dev/null +++ b/feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/navigation/TraineeNotificationNavigation.kt @@ -0,0 +1,25 @@ +package co.kr.tnt.trainee.notification.navigation + +import androidx.navigation.NavController +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavOptionsBuilder +import androidx.navigation.compose.composable +import co.kr.tnt.navigation.Route +import co.kr.tnt.trainee.notification.TraineeNotificationRoute + +fun NavController.navigateToTraineeNotification( + navOptions: NavOptionsBuilder.() -> Unit = {}, +) = navigate( + route = Route.TraineeNotification, + builder = navOptions, +) + +fun NavGraphBuilder.traineeNotification( + navigateToPrevious: () -> Unit, +) { + composable { + TraineeNotificationRoute( + navigateToPrevious = navigateToPrevious, + ) + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 5f15ee62..d86f0990 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -51,5 +51,6 @@ include( ":feature:trainee:signup", ":feature:trainee:connect", ":feature:trainee:mypage", + ":feature:trainee:notification", ":feature:webview", ) From dbccdb7651d544bf745d3b6b5ed92315e13735ed Mon Sep 17 00:00:00 2001 From: SeonJeongk Date: Sun, 2 Feb 2025 18:11:49 +0900 Subject: [PATCH 05/11] =?UTF-8?q?[TNT-189]=20refactor:=20=EC=95=8C?= =?UTF-8?q?=EB=A6=BC=20=EC=95=84=EC=9D=B4=EC=BD=98=20=EB=AA=A8=EB=8D=B8=20?= =?UTF-8?q?NotificationType=20->=20NotificationIcon=EC=9C=BC=EB=A1=9C=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 --- .../tnt/designsystem/component/notification/Notification.kt | 6 +++--- .../model/{NotificationType.kt => NotificationIcon.kt} | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) rename core/designsystem/src/main/java/co/kr/tnt/designsystem/component/notification/model/{NotificationType.kt => NotificationIcon.kt} (80%) diff --git a/core/designsystem/src/main/java/co/kr/tnt/designsystem/component/notification/Notification.kt b/core/designsystem/src/main/java/co/kr/tnt/designsystem/component/notification/Notification.kt index 0e6cd668..8fe0edbf 100644 --- a/core/designsystem/src/main/java/co/kr/tnt/designsystem/component/notification/Notification.kt +++ b/core/designsystem/src/main/java/co/kr/tnt/designsystem/component/notification/Notification.kt @@ -14,12 +14,12 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import co.kr.tnt.designsystem.component.notification.model.NotificationType +import co.kr.tnt.designsystem.component.notification.model.NotificationIcon import co.kr.tnt.designsystem.theme.TnTTheme @Composable fun TnTNotification( - type: NotificationType, + type: NotificationIcon, title: String, contents: String, time: String, @@ -78,7 +78,7 @@ fun TnTNotification( private fun TnTNotificationPreview() { TnTTheme { TnTNotification( - type = NotificationType.LINK, + type = NotificationIcon.LINK, title = "알림 문구", contents = "알림 상세 문구", time = "2분전", diff --git a/core/designsystem/src/main/java/co/kr/tnt/designsystem/component/notification/model/NotificationType.kt b/core/designsystem/src/main/java/co/kr/tnt/designsystem/component/notification/model/NotificationIcon.kt similarity index 80% rename from core/designsystem/src/main/java/co/kr/tnt/designsystem/component/notification/model/NotificationType.kt rename to core/designsystem/src/main/java/co/kr/tnt/designsystem/component/notification/model/NotificationIcon.kt index 521f0f05..33e10c31 100644 --- a/core/designsystem/src/main/java/co/kr/tnt/designsystem/component/notification/model/NotificationType.kt +++ b/core/designsystem/src/main/java/co/kr/tnt/designsystem/component/notification/model/NotificationIcon.kt @@ -2,7 +2,7 @@ package co.kr.tnt.designsystem.component.notification.model import co.kr.tnt.core.designsystem.R -enum class NotificationType(val icon: Int) { +enum class NotificationIcon(val icon: Int) { LINK(R.drawable.ic_link_notif), SCHEDULE(R.drawable.ic_schedule_notif), } From f5697e7450942de2b7d8d4b3c384026ca7c57109 Mon Sep 17 00:00:00 2001 From: SeonJeongk Date: Sun, 2 Feb 2025 18:31:55 +0900 Subject: [PATCH 06/11] =?UTF-8?q?[TNT-189]=20feat:=20=ED=8A=B8=EB=A0=88?= =?UTF-8?q?=EC=9D=B4=EB=8B=88=20=EC=95=8C=EB=A6=BC=20=EB=A6=AC=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../co/kr/tnt/ui/model/NotificationState.kt | 32 ++++++ core/ui/src/main/res/values/strings.xml | 1 + .../kr/tnt/domain/model/NotificationInfo.kt | 26 +++++ .../TraineeNotificationContract.kt | 21 ++++ .../notification/TraineeNotificationScreen.kt | 103 +++++++++++++++--- .../TraineeNotificationViewModel.kt | 54 ++++++++- 6 files changed, 222 insertions(+), 15 deletions(-) create mode 100644 core/ui/src/main/java/co/kr/tnt/ui/model/NotificationState.kt create mode 100644 domain/src/main/java/co/kr/tnt/domain/model/NotificationInfo.kt create mode 100644 feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/TraineeNotificationContract.kt diff --git a/core/ui/src/main/java/co/kr/tnt/ui/model/NotificationState.kt b/core/ui/src/main/java/co/kr/tnt/ui/model/NotificationState.kt new file mode 100644 index 00000000..75e9a0c4 --- /dev/null +++ b/core/ui/src/main/java/co/kr/tnt/ui/model/NotificationState.kt @@ -0,0 +1,32 @@ +package co.kr.tnt.ui.model + +import co.kr.tnt.designsystem.component.notification.model.NotificationIcon +import co.kr.tnt.domain.model.NotificationInfo +import co.kr.tnt.domain.model.NotificationType + +data class NotificationState( + val type: NotificationIcon, + val title: String, + val contents: String, + val time: String, + val isChecked: Boolean = true, +) { + companion object { + fun fromDomain(domain: NotificationInfo): NotificationState { + return NotificationState( + type = when (domain.type) { + NotificationType.LINK -> NotificationIcon.LINK + NotificationType.SCHEDULE -> NotificationIcon.SCHEDULE + }, + title = domain.title, + contents = domain.contents, + time = domain.time, + isChecked = domain.isChecked, + ) + } + } +} + +fun List.toUiStateList(): List { + return this.map { NotificationState.fromDomain(it) } +} diff --git a/core/ui/src/main/res/values/strings.xml b/core/ui/src/main/res/values/strings.xml index 87b2e5bb..3fd81050 100644 --- a/core/ui/src/main/res/values/strings.xml +++ b/core/ui/src/main/res/values/strings.xml @@ -36,6 +36,7 @@ kg 알림 + 최근 받은 알림이 없어요 아침 diff --git a/domain/src/main/java/co/kr/tnt/domain/model/NotificationInfo.kt b/domain/src/main/java/co/kr/tnt/domain/model/NotificationInfo.kt new file mode 100644 index 00000000..2c96f24b --- /dev/null +++ b/domain/src/main/java/co/kr/tnt/domain/model/NotificationInfo.kt @@ -0,0 +1,26 @@ +package co.kr.tnt.domain.model + +data class NotificationInfo( + val type: NotificationType, + val title: String, + val contents: String, + val time: String, + val isChecked: Boolean, +) + +// TODO API 나오면 수정 필요 +enum class NotificationType { + LINK, + SCHEDULE, + ; + + companion object { + fun from(type: String): NotificationType { + return when (type) { + "LINK" -> LINK + "SCHEDULE" -> SCHEDULE + else -> throw IllegalArgumentException("지원하지 않는 $type 입니다.") + } + } + } +} diff --git a/feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/TraineeNotificationContract.kt b/feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/TraineeNotificationContract.kt new file mode 100644 index 00000000..70ed69d1 --- /dev/null +++ b/feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/TraineeNotificationContract.kt @@ -0,0 +1,21 @@ +package co.kr.tnt.trainee.notification + +import co.kr.tnt.ui.base.UiEvent +import co.kr.tnt.ui.base.UiSideEffect +import co.kr.tnt.ui.base.UiState +import co.kr.tnt.ui.model.NotificationState + +internal class TraineeNotificationContract { + data class TraineeNotificationUiState( + val notifications: List = emptyList(), + ) : UiState + + sealed interface TraineeNotificationUiEvent : UiEvent { + data object OnBackClick : TraineeNotificationUiEvent + } + + sealed interface TraineeNotificationEffect : UiSideEffect { + data class ShowToast(val message: String) : TraineeNotificationEffect + data object NavigateToPrevious : TraineeNotificationEffect + } +} diff --git a/feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/TraineeNotificationScreen.kt b/feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/TraineeNotificationScreen.kt index 33a8c4dc..88821e84 100644 --- a/feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/TraineeNotificationScreen.kt +++ b/feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/TraineeNotificationScreen.kt @@ -1,46 +1,99 @@ package co.kr.tnt.trainee.notification -import androidx.compose.foundation.layout.Column +import android.widget.Toast +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle import co.kr.tnt.designsystem.component.TnTTopBarWithBackButton +import co.kr.tnt.designsystem.component.notification.TnTNotification +import co.kr.tnt.designsystem.component.notification.model.NotificationIcon import co.kr.tnt.designsystem.theme.TnTTheme +import co.kr.tnt.trainee.notification.TraineeNotificationContract.TraineeNotificationUiState +import co.kr.tnt.ui.model.NotificationState import co.kr.tnt.core.ui.R as uiResource @Composable internal fun TraineeNotificationRoute( navigateToPrevious: () -> Unit, + viewModel: TraineeNotificationViewModel = hiltViewModel(), ) { + val context = LocalContext.current + val uiState by viewModel.uiState.collectAsStateWithLifecycle() + TraineeNotificationScreen( - navigateToPrevious = navigateToPrevious, + state = uiState, + onBackClick = navigateToPrevious, ) + + LaunchedEffect(viewModel.effect) { + viewModel.effect.collect { effect -> + when (effect) { + TraineeNotificationContract.TraineeNotificationEffect.NavigateToPrevious -> navigateToPrevious() + is TraineeNotificationContract.TraineeNotificationEffect.ShowToast -> { + Toast.makeText(context, effect.message, Toast.LENGTH_SHORT).show() + } + } + } + } } @Composable -fun TraineeNotificationScreen( - navigateToPrevious: () -> Unit, +private fun TraineeNotificationScreen( + state: TraineeNotificationUiState, + onBackClick: () -> Unit, ) { Scaffold( topBar = { TnTTopBarWithBackButton( title = stringResource(uiResource.string.notification), - onBackClick = navigateToPrevious, + onBackClick = onBackClick, ) }, - contentColor = TnTTheme.colors.commonColors.Common0, + containerColor = TnTTheme.colors.commonColors.Common0, ) { innerPadding -> - Column( - modifier = Modifier - .fillMaxSize() - .padding(innerPadding), - ) { - Text(text = "text") + Box(modifier = Modifier.fillMaxSize()) { + if (state.notifications.isEmpty()) { + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center, + ) { + Text( + text = stringResource(uiResource.string.no_recent_notifications), + style = TnTTheme.typography.label1Medium, + color = TnTTheme.colors.neutralColors.Neutral400, + ) + } + } else { + LazyColumn( + modifier = Modifier + .fillMaxSize() + .padding(innerPadding), + ) { + items(state.notifications) { notification -> + TnTNotification( + type = notification.type, + title = notification.title, + contents = notification.contents, + time = notification.time, + isChecked = notification.isChecked, + ) + } + } + } } } } @@ -49,8 +102,32 @@ fun TraineeNotificationScreen( @Composable private fun TraineeNotificationScreenPreview() { TnTTheme { + val sampleNotifications = listOf( + NotificationState( + type = NotificationIcon.LINK, + title = "트레이너 연결 해제", + contents = "박헬린 트레이너가 연결을 끊었어요", + time = "3분 전", + isChecked = false, + ), + NotificationState( + type = NotificationIcon.LINK, + title = "트레이너 연결 해제", + contents = "김헬스 트레이너가 연결을 끊었어요", + time = "12시간 전", + isChecked = false, + ), + NotificationState( + type = NotificationIcon.LINK, + title = "트레이너 연결 해제", + contents = "김피티 트레이너가 연결을 끊었어요", + time = "2025/01/01", + isChecked = true, + ), + ) TraineeNotificationScreen( - navigateToPrevious = {}, + onBackClick = {}, + state = TraineeNotificationUiState(notifications = sampleNotifications), ) } } diff --git a/feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/TraineeNotificationViewModel.kt b/feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/TraineeNotificationViewModel.kt index efeeddee..0981020a 100644 --- a/feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/TraineeNotificationViewModel.kt +++ b/feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/TraineeNotificationViewModel.kt @@ -1,8 +1,58 @@ package co.kr.tnt.trainee.notification -import androidx.lifecycle.ViewModel +import co.kr.tnt.designsystem.component.notification.model.NotificationIcon +import co.kr.tnt.trainee.notification.TraineeNotificationContract.TraineeNotificationEffect +import co.kr.tnt.trainee.notification.TraineeNotificationContract.TraineeNotificationUiEvent +import co.kr.tnt.trainee.notification.TraineeNotificationContract.TraineeNotificationUiState +import co.kr.tnt.ui.base.BaseViewModel +import co.kr.tnt.ui.model.NotificationState import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject @HiltViewModel -internal class TraineeNotificationViewModel @Inject constructor() : ViewModel() +internal class TraineeNotificationViewModel @Inject constructor() : + BaseViewModel( + TraineeNotificationUiState(), + ) { + init { + getNotification() + } + + override suspend fun handleEvent(event: TraineeNotificationUiEvent) { + when (event) { + TraineeNotificationUiEvent.OnBackClick -> navigateToBack() + } + } + + private fun getNotification() { + // TODO 알림 불러오기 + val sampleNotifications = listOf( + NotificationState( + type = NotificationIcon.LINK, + title = "트레이너 연결 해제", + contents = "박헬린 트레이너가 연결을 끊었어요", + time = "3분 전", + isChecked = false, + ), + NotificationState( + type = NotificationIcon.LINK, + title = "트레이너 연결 해제", + contents = "김헬스 트레이너가 연결을 끊었어요", + time = "12시간 전", + isChecked = true, + ), + NotificationState( + type = NotificationIcon.LINK, + title = "트레이너 연결 해제", + contents = "김피티 트레이너가 연결을 끊었어요", + time = "2025/02/01", + isChecked = true, + ), + ) + updateState { copy(notifications = sampleNotifications) } + } + + private fun navigateToBack() { + sendEffect(TraineeNotificationEffect.NavigateToPrevious) + } + } From b929fbb5bab91f6a55319f2fdaec3da82a259bf3 Mon Sep 17 00:00:00 2001 From: SeonJeongk Date: Sun, 2 Feb 2025 19:51:15 +0900 Subject: [PATCH 07/11] =?UTF-8?q?[TNT-189]=20chore:=20=ED=8A=B8=EB=A0=88?= =?UTF-8?q?=EC=9D=B4=EB=8B=88=20=EC=95=8C=EB=A6=BC=20=EB=AA=A8=EB=93=88=20?= =?UTF-8?q?setNamespace=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- feature/trainee/notification/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feature/trainee/notification/build.gradle.kts b/feature/trainee/notification/build.gradle.kts index 095303af..f4bed3aa 100644 --- a/feature/trainee/notification/build.gradle.kts +++ b/feature/trainee/notification/build.gradle.kts @@ -5,7 +5,7 @@ plugins { } android { - setNamespace("feature.notification") + setNamespace("feature.trainee.notification") } dependencies { From 70f7c2ac3930cf251922b7a68ef2ce2e37d69800 Mon Sep 17 00:00:00 2001 From: SeonJeongk Date: Sun, 2 Feb 2025 23:17:31 +0900 Subject: [PATCH 08/11] =?UTF-8?q?[TNT-189]=20feat:=20=EC=95=8C=EB=A6=BC=20?= =?UTF-8?q?=EC=8B=9C=EA=B0=84=20=EB=B3=80=ED=99=98=20Util=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../co/kr/tnt/ui/model/NotificationState.kt | 3 ++- .../tnt/domain/util/NotificationTimeUtil.kt | 26 +++++++++++++++++++ .../TraineeNotificationViewModel.kt | 25 +++++++++--------- 3 files changed, 41 insertions(+), 13 deletions(-) create mode 100644 domain/src/main/java/co/kr/tnt/domain/util/NotificationTimeUtil.kt diff --git a/core/ui/src/main/java/co/kr/tnt/ui/model/NotificationState.kt b/core/ui/src/main/java/co/kr/tnt/ui/model/NotificationState.kt index 75e9a0c4..44b6a315 100644 --- a/core/ui/src/main/java/co/kr/tnt/ui/model/NotificationState.kt +++ b/core/ui/src/main/java/co/kr/tnt/ui/model/NotificationState.kt @@ -3,6 +3,7 @@ package co.kr.tnt.ui.model import co.kr.tnt.designsystem.component.notification.model.NotificationIcon import co.kr.tnt.domain.model.NotificationInfo import co.kr.tnt.domain.model.NotificationType +import co.kr.tnt.domain.util.NotificationTimeUtil data class NotificationState( val type: NotificationIcon, @@ -20,7 +21,7 @@ data class NotificationState( }, title = domain.title, contents = domain.contents, - time = domain.time, + time = NotificationTimeUtil.formatTime(domain.time), isChecked = domain.isChecked, ) } diff --git a/domain/src/main/java/co/kr/tnt/domain/util/NotificationTimeUtil.kt b/domain/src/main/java/co/kr/tnt/domain/util/NotificationTimeUtil.kt new file mode 100644 index 00000000..dc61be5b --- /dev/null +++ b/domain/src/main/java/co/kr/tnt/domain/util/NotificationTimeUtil.kt @@ -0,0 +1,26 @@ +package co.kr.tnt.domain.util + +import java.time.LocalDateTime +import java.time.format.DateTimeFormatter +import java.time.temporal.ChronoUnit +import java.util.Locale + +object NotificationTimeUtil { + fun formatTime(notificationTime: String): String { + val now = LocalDateTime.now() + val time = LocalDateTime.parse(notificationTime, DateTimeFormatter.ISO_DATE_TIME) + + val minutesDiff = ChronoUnit.MINUTES.between(time, now) + val hoursDiff = ChronoUnit.HOURS.between(time, now) + + return when { + minutesDiff < 1 -> "방금" + minutesDiff < 60 -> "${minutesDiff}분 전" + hoursDiff < 24 -> "${hoursDiff}시간 전" + else -> { + val dateFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd", Locale.getDefault()) + time.format(dateFormatter) + } + } + } +} diff --git a/feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/TraineeNotificationViewModel.kt b/feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/TraineeNotificationViewModel.kt index 0981020a..ec782d65 100644 --- a/feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/TraineeNotificationViewModel.kt +++ b/feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/TraineeNotificationViewModel.kt @@ -1,11 +1,12 @@ package co.kr.tnt.trainee.notification -import co.kr.tnt.designsystem.component.notification.model.NotificationIcon +import co.kr.tnt.domain.model.NotificationInfo +import co.kr.tnt.domain.model.NotificationType import co.kr.tnt.trainee.notification.TraineeNotificationContract.TraineeNotificationEffect import co.kr.tnt.trainee.notification.TraineeNotificationContract.TraineeNotificationUiEvent import co.kr.tnt.trainee.notification.TraineeNotificationContract.TraineeNotificationUiState import co.kr.tnt.ui.base.BaseViewModel -import co.kr.tnt.ui.model.NotificationState +import co.kr.tnt.ui.model.toUiStateList import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject @@ -27,29 +28,29 @@ internal class TraineeNotificationViewModel @Inject constructor() : private fun getNotification() { // TODO 알림 불러오기 val sampleNotifications = listOf( - NotificationState( - type = NotificationIcon.LINK, + NotificationInfo( + type = NotificationType.LINK, title = "트레이너 연결 해제", contents = "박헬린 트레이너가 연결을 끊었어요", - time = "3분 전", + time = "2025-02-02T23:12:00", isChecked = false, ), - NotificationState( - type = NotificationIcon.LINK, + NotificationInfo( + type = NotificationType.LINK, title = "트레이너 연결 해제", contents = "김헬스 트레이너가 연결을 끊었어요", - time = "12시간 전", + time = "2025-02-02T23:03:00", isChecked = true, ), - NotificationState( - type = NotificationIcon.LINK, + NotificationInfo( + type = NotificationType.LINK, title = "트레이너 연결 해제", contents = "김피티 트레이너가 연결을 끊었어요", - time = "2025/02/01", + time = "2025-01-31T22:29:00", isChecked = true, ), ) - updateState { copy(notifications = sampleNotifications) } + updateState { copy(notifications = sampleNotifications.toUiStateList()) } } private fun navigateToBack() { From d5e4b384f8175be59bc1318397affc5f2cfbd1f4 Mon Sep 17 00:00:00 2001 From: SeonJeongk Date: Mon, 3 Feb 2025 01:18:29 +0900 Subject: [PATCH 09/11] =?UTF-8?q?[TNT-189]=20fix:=20onBackClick=20?= =?UTF-8?q?=EC=9D=B4=EB=B2=A4=ED=8A=B8=EB=A1=9C=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kr/tnt/trainee/notification/TraineeNotificationScreen.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/TraineeNotificationScreen.kt b/feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/TraineeNotificationScreen.kt index 88821e84..13c65717 100644 --- a/feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/TraineeNotificationScreen.kt +++ b/feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/TraineeNotificationScreen.kt @@ -22,6 +22,7 @@ import co.kr.tnt.designsystem.component.TnTTopBarWithBackButton import co.kr.tnt.designsystem.component.notification.TnTNotification import co.kr.tnt.designsystem.component.notification.model.NotificationIcon import co.kr.tnt.designsystem.theme.TnTTheme +import co.kr.tnt.trainee.notification.TraineeNotificationContract.TraineeNotificationUiEvent import co.kr.tnt.trainee.notification.TraineeNotificationContract.TraineeNotificationUiState import co.kr.tnt.ui.model.NotificationState import co.kr.tnt.core.ui.R as uiResource @@ -36,7 +37,7 @@ internal fun TraineeNotificationRoute( TraineeNotificationScreen( state = uiState, - onBackClick = navigateToPrevious, + onBackClick = { viewModel.setEvent(TraineeNotificationUiEvent.OnBackClick) }, ) LaunchedEffect(viewModel.effect) { From dda4a3daa74541dda3e1e294911a9ccc5b7cb225 Mon Sep 17 00:00:00 2001 From: SeonJeongk Date: Mon, 3 Feb 2025 22:22:16 +0900 Subject: [PATCH 10/11] =?UTF-8?q?[TNT-189]=20fix:=20NotificationTimeUtil?= =?UTF-8?q?=20domain=EC=97=90=EC=84=9C=20core:ui=20=EB=AA=A8=EB=93=88?= =?UTF-8?q?=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/ui/src/main/java/co/kr/tnt/ui/model/NotificationState.kt | 2 +- .../ui/src/main/java/co/kr/tnt/ui}/util/NotificationTimeUtil.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename {domain/src/main/java/co/kr/tnt/domain => core/ui/src/main/java/co/kr/tnt/ui}/util/NotificationTimeUtil.kt (96%) diff --git a/core/ui/src/main/java/co/kr/tnt/ui/model/NotificationState.kt b/core/ui/src/main/java/co/kr/tnt/ui/model/NotificationState.kt index 44b6a315..e70b4a6b 100644 --- a/core/ui/src/main/java/co/kr/tnt/ui/model/NotificationState.kt +++ b/core/ui/src/main/java/co/kr/tnt/ui/model/NotificationState.kt @@ -3,7 +3,7 @@ package co.kr.tnt.ui.model import co.kr.tnt.designsystem.component.notification.model.NotificationIcon import co.kr.tnt.domain.model.NotificationInfo import co.kr.tnt.domain.model.NotificationType -import co.kr.tnt.domain.util.NotificationTimeUtil +import co.kr.tnt.ui.util.NotificationTimeUtil data class NotificationState( val type: NotificationIcon, diff --git a/domain/src/main/java/co/kr/tnt/domain/util/NotificationTimeUtil.kt b/core/ui/src/main/java/co/kr/tnt/ui/util/NotificationTimeUtil.kt similarity index 96% rename from domain/src/main/java/co/kr/tnt/domain/util/NotificationTimeUtil.kt rename to core/ui/src/main/java/co/kr/tnt/ui/util/NotificationTimeUtil.kt index dc61be5b..cf450903 100644 --- a/domain/src/main/java/co/kr/tnt/domain/util/NotificationTimeUtil.kt +++ b/core/ui/src/main/java/co/kr/tnt/ui/util/NotificationTimeUtil.kt @@ -1,4 +1,4 @@ -package co.kr.tnt.domain.util +package co.kr.tnt.ui.util import java.time.LocalDateTime import java.time.format.DateTimeFormatter From f7592883a295813fef4f5c1c978c3c1cb6bc5191 Mon Sep 17 00:00:00 2001 From: SeonJeongk Date: Mon, 3 Feb 2025 23:57:14 +0900 Subject: [PATCH 11/11] =?UTF-8?q?[TNT-189]=20fix:=20=EB=8F=84=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20NotificationInfo=20time=EC=9D=84=20LocalDateTime?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/co/kr/tnt/ui/model/NotificationState.kt | 5 +++-- .../java/co/kr/tnt/ui/util/NotificationTimeUtil.kt | 11 +++++------ .../java/co/kr/tnt/domain/model/NotificationInfo.kt | 4 +++- .../notification/TraineeNotificationViewModel.kt | 10 +++++++--- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/core/ui/src/main/java/co/kr/tnt/ui/model/NotificationState.kt b/core/ui/src/main/java/co/kr/tnt/ui/model/NotificationState.kt index e70b4a6b..e2f65873 100644 --- a/core/ui/src/main/java/co/kr/tnt/ui/model/NotificationState.kt +++ b/core/ui/src/main/java/co/kr/tnt/ui/model/NotificationState.kt @@ -3,7 +3,7 @@ package co.kr.tnt.ui.model import co.kr.tnt.designsystem.component.notification.model.NotificationIcon import co.kr.tnt.domain.model.NotificationInfo import co.kr.tnt.domain.model.NotificationType -import co.kr.tnt.ui.util.NotificationTimeUtil +import co.kr.tnt.ui.util.NotificationTimeFormatter data class NotificationState( val type: NotificationIcon, @@ -14,6 +14,7 @@ data class NotificationState( ) { companion object { fun fromDomain(domain: NotificationInfo): NotificationState { + val timeFormatter = NotificationTimeFormatter() return NotificationState( type = when (domain.type) { NotificationType.LINK -> NotificationIcon.LINK @@ -21,7 +22,7 @@ data class NotificationState( }, title = domain.title, contents = domain.contents, - time = NotificationTimeUtil.formatTime(domain.time), + time = timeFormatter.formatTime(domain.time), isChecked = domain.isChecked, ) } diff --git a/core/ui/src/main/java/co/kr/tnt/ui/util/NotificationTimeUtil.kt b/core/ui/src/main/java/co/kr/tnt/ui/util/NotificationTimeUtil.kt index cf450903..74d03987 100644 --- a/core/ui/src/main/java/co/kr/tnt/ui/util/NotificationTimeUtil.kt +++ b/core/ui/src/main/java/co/kr/tnt/ui/util/NotificationTimeUtil.kt @@ -5,13 +5,12 @@ import java.time.format.DateTimeFormatter import java.time.temporal.ChronoUnit import java.util.Locale -object NotificationTimeUtil { - fun formatTime(notificationTime: String): String { +class NotificationTimeFormatter { + fun formatTime(notificationTime: LocalDateTime): String { val now = LocalDateTime.now() - val time = LocalDateTime.parse(notificationTime, DateTimeFormatter.ISO_DATE_TIME) - val minutesDiff = ChronoUnit.MINUTES.between(time, now) - val hoursDiff = ChronoUnit.HOURS.between(time, now) + val minutesDiff = ChronoUnit.MINUTES.between(notificationTime, now) + val hoursDiff = ChronoUnit.HOURS.between(notificationTime, now) return when { minutesDiff < 1 -> "방금" @@ -19,7 +18,7 @@ object NotificationTimeUtil { hoursDiff < 24 -> "${hoursDiff}시간 전" else -> { val dateFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd", Locale.getDefault()) - time.format(dateFormatter) + notificationTime.format(dateFormatter) } } } diff --git a/domain/src/main/java/co/kr/tnt/domain/model/NotificationInfo.kt b/domain/src/main/java/co/kr/tnt/domain/model/NotificationInfo.kt index 2c96f24b..53ef6bcb 100644 --- a/domain/src/main/java/co/kr/tnt/domain/model/NotificationInfo.kt +++ b/domain/src/main/java/co/kr/tnt/domain/model/NotificationInfo.kt @@ -1,10 +1,12 @@ package co.kr.tnt.domain.model +import java.time.LocalDateTime + data class NotificationInfo( val type: NotificationType, val title: String, val contents: String, - val time: String, + val time: LocalDateTime, val isChecked: Boolean, ) diff --git a/feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/TraineeNotificationViewModel.kt b/feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/TraineeNotificationViewModel.kt index ec782d65..43b534bb 100644 --- a/feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/TraineeNotificationViewModel.kt +++ b/feature/trainee/notification/src/main/java/co/kr/tnt/trainee/notification/TraineeNotificationViewModel.kt @@ -8,6 +8,8 @@ import co.kr.tnt.trainee.notification.TraineeNotificationContract.TraineeNotific import co.kr.tnt.ui.base.BaseViewModel import co.kr.tnt.ui.model.toUiStateList import dagger.hilt.android.lifecycle.HiltViewModel +import java.time.LocalDateTime +import java.time.format.DateTimeFormatter import javax.inject.Inject @HiltViewModel @@ -27,26 +29,28 @@ internal class TraineeNotificationViewModel @Inject constructor() : private fun getNotification() { // TODO 알림 불러오기 + val formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME + val sampleNotifications = listOf( NotificationInfo( type = NotificationType.LINK, title = "트레이너 연결 해제", contents = "박헬린 트레이너가 연결을 끊었어요", - time = "2025-02-02T23:12:00", + time = LocalDateTime.parse("2025-02-03T23:12:00", formatter), isChecked = false, ), NotificationInfo( type = NotificationType.LINK, title = "트레이너 연결 해제", contents = "김헬스 트레이너가 연결을 끊었어요", - time = "2025-02-02T23:03:00", + time = LocalDateTime.parse("2025-02-03T23:03:00", formatter), isChecked = true, ), NotificationInfo( type = NotificationType.LINK, title = "트레이너 연결 해제", contents = "김피티 트레이너가 연결을 끊었어요", - time = "2025-01-31T22:29:00", + time = LocalDateTime.parse("2025-02-02T22:29:00", formatter), isChecked = true, ), )