From 4f38391a0cbd3a1fe5e96efb44c7f8a6c034ab7e Mon Sep 17 00:00:00 2001 From: ashxom Date: Wed, 22 Jul 2026 16:42:12 +0900 Subject: [PATCH 1/4] =?UTF-8?q?refactor=20::=20=EA=B3=B5=EC=A7=80=20?= =?UTF-8?q?=ED=83=AD=EC=9D=98=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=86=8C?= =?UTF-8?q?=EC=8A=A4=EB=A5=BC=20=EA=B3=B5=EC=A7=80=20API=EB=A1=9C=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../viewmodel/NotificationViewModel.kt | 86 ++++++++++++------- 1 file changed, 56 insertions(+), 30 deletions(-) diff --git a/feature/src/main/kotlin/team/aliens/dms/android/feature/notification/viewmodel/NotificationViewModel.kt b/feature/src/main/kotlin/team/aliens/dms/android/feature/notification/viewmodel/NotificationViewModel.kt index d50b531fe..8263d5a83 100644 --- a/feature/src/main/kotlin/team/aliens/dms/android/feature/notification/viewmodel/NotificationViewModel.kt +++ b/feature/src/main/kotlin/team/aliens/dms/android/feature/notification/viewmodel/NotificationViewModel.kt @@ -6,48 +6,70 @@ import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import team.aliens.dms.android.core.ui.viewmodel.BaseStateViewModel +import team.aliens.dms.android.data.notice.repository.NoticeRepository import team.aliens.dms.android.data.notification.model.NotificationTopic import team.aliens.dms.android.data.notification.repository.NotificationRepository import team.aliens.dms.android.data.point.model.PointType import team.aliens.dms.android.shared.date.toElapsedText import team.aliens.dms.android.shared.date.util.now -import java.time.LocalDateTime import java.util.UUID import javax.inject.Inject @HiltViewModel internal class NotificationViewModel @Inject constructor( private val notificationRepository: NotificationRepository, -) : BaseStateViewModel(NotificationState()) { + private val noticeRepository: NoticeRepository, +) : BaseStateViewModel( + NotificationState(), +) { init { fetchNotifications() + fetchNotices() } private fun fetchNotifications() { viewModelScope.launch(Dispatchers.IO) { - notificationRepository.fetchNotifications().onSuccess { notifications -> - val notificationsUi = notifications.map { notification -> NotificationUi( - id = notification.id, - title = notification.title, - content = notification.content, - createdAt = notification.createdAt, - isRead = notification.isRead, - linkId = notification.linkId, - topic = notification.topic, - pointDetailTopic = notification.pointDetailTopic, - elapsedText = notification.createdAt.toElapsedText(now), - ) } - val notification = notificationsUi.filter { it.topic == NotificationTopic.POINT } - val notices = notificationsUi.filter { it.topic == NotificationTopic.NOTICE } + notificationRepository.fetchNotifications() + .onSuccess { notifications -> + val notificationsUi = notifications + .filter { notification -> notification.topic == NotificationTopic.POINT } + .map { notification -> + NotificationUi( + id = notification.id, + pointDetailTopic = notification.pointDetailTopic, + title = notification.title, + content = notification.content, + isRead = notification.isRead, + elapsedText = notification.createdAt.toElapsedText(now), + ) + } - setState { it.copy( - notifications = notification, - notices = notices - ) } - }.onFailure { - sendEffect(NotificationSideEffect.FailFetchNotification) - } + setState { it.copy(notifications = notificationsUi) } + } + .onFailure { + sendEffect(NotificationSideEffect.FailFetchNotification) + } + } + } + + private fun fetchNotices() { + viewModelScope.launch(Dispatchers.IO) { + noticeRepository.fetchNotices() + .onSuccess { notices -> + val noticesUi = notices.map { notice -> + NoticeUi( + id = notice.id, + title = notice.title, + elapsedText = notice.createdAt.toElapsedText(now), + ) + } + + setState { it.copy(notices = noticesUi) } + } + .onFailure { + sendEffect(NotificationSideEffect.FailFetchNotice) + } } } @@ -63,30 +85,34 @@ internal class NotificationViewModel @Inject constructor( ) } } - } @Immutable internal data class NotificationUi( val id: UUID, - val topic: NotificationTopic, val pointDetailTopic: PointType, - val linkId: UUID, val title: String, val content: String, - val createdAt: LocalDateTime, val isRead: Boolean, val elapsedText: String, ) +@Immutable +internal data class NoticeUi( + val id: UUID, + val title: String, + val elapsedText: String, +) + @Immutable internal data class NotificationState( val isRecent: Boolean = false, - val notices: List = emptyList(), + val notices: List = emptyList(), val notifications: List = emptyList(), ) internal sealed interface NotificationSideEffect { - object FailFetchNotification : NotificationSideEffect - object FailUpdateNotification : NotificationSideEffect + data object FailFetchNotification : NotificationSideEffect + data object FailFetchNotice : NotificationSideEffect + data object FailUpdateNotification : NotificationSideEffect } From 397d1cd6bb4a3d77f22f00bdcde3aa9ccfaae76a Mon Sep 17 00:00:00 2001 From: ashxom Date: Wed, 22 Jul 2026 16:42:35 +0900 Subject: [PATCH 2/4] =?UTF-8?q?fix=20::=20=EA=B3=B5=EC=A7=80=20=ED=83=AD?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EA=B3=B5=EC=A7=80=20ID=EB=A1=9C=20?= =?UTF-8?q?=EC=83=81=EC=84=B8=20=ED=99=94=EB=A9=B4=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../notification/ui/NotificationScreen.kt | 71 ++++++++++--------- 1 file changed, 39 insertions(+), 32 deletions(-) diff --git a/feature/src/main/kotlin/team/aliens/dms/android/feature/notification/ui/NotificationScreen.kt b/feature/src/main/kotlin/team/aliens/dms/android/feature/notification/ui/NotificationScreen.kt index bd6c23d55..85b323405 100644 --- a/feature/src/main/kotlin/team/aliens/dms/android/feature/notification/ui/NotificationScreen.kt +++ b/feature/src/main/kotlin/team/aliens/dms/android/feature/notification/ui/NotificationScreen.kt @@ -50,6 +50,7 @@ import team.aliens.dms.android.feature.notification.viewmodel.NotificationSideEf import team.aliens.dms.android.feature.notification.viewmodel.NotificationState import team.aliens.dms.android.feature.notification.viewmodel.NotificationUi import team.aliens.dms.android.feature.notification.viewmodel.NotificationViewModel +import team.aliens.dms.android.feature.notification.viewmodel.NoticeUi import java.util.UUID @Composable @@ -77,10 +78,18 @@ internal fun Notification( viewModel.sideEffect.collect { when (it) { is NotificationSideEffect.FailFetchNotification -> updatedOnShowSnackBar( - DmsSnackBarType.ERROR, "알림 조회를 실패했어요" + DmsSnackBarType.ERROR, + "알림 조회를 실패했어요", ) + + is NotificationSideEffect.FailFetchNotice -> updatedOnShowSnackBar( + DmsSnackBarType.ERROR, + "공지 조회를 실패했어요", + ) + is NotificationSideEffect.FailUpdateNotification -> updatedOnShowSnackBar( - DmsSnackBarType.ERROR, "업데이트 실패 했어요" + DmsSnackBarType.ERROR, + "업데이트 실패 했어요", ) } } @@ -97,10 +106,7 @@ internal fun Notification( } }, onBackClick = onBackClick, - onNotificationDetailClick = { linkId, notificationId -> - viewModel.updateNotificationReadStatus(notificationId) - onNavigateNotificationDetailClick(linkId) - }, + onNotificationDetailClick = onNavigateNotificationDetailClick, onNotificationClick = { point, notificationId -> viewModel.updateNotificationReadStatus(notificationId) onNavigatePointHistory(point) @@ -116,7 +122,7 @@ private fun NotificationScreen( tabIndex: Int, onTabClick: (Int) -> Unit, onBackClick: () -> Unit, - onNotificationDetailClick: (UUID, UUID) -> Unit, + onNotificationDetailClick: (UUID) -> Unit, onNotificationClick: (PointType, UUID) -> Unit, ) { Column( @@ -126,9 +132,7 @@ private fun NotificationScreen( .systemBarsPadding(), ) { DmsTopAppBar(onBackClick = onBackClick) - DmsTabRow( - selectedTabIndex = tabIndex, - ) { + DmsTabRow(selectedTabIndex = tabIndex) { tabData.forEachIndexed { index, text -> DmsTab( selected = tabIndex == index, @@ -140,7 +144,7 @@ private fun NotificationScreen( HorizontalPager( modifier = Modifier.fillMaxWidth(), state = pagerState, - beyondViewportPageCount = 1 + beyondViewportPageCount = 1, ) { page -> if (page == 0) { NotificationItems( @@ -154,7 +158,6 @@ private fun NotificationScreen( ) } } - } } @@ -164,13 +167,11 @@ internal fun NotificationItems( onNotificationClick: (PointType, UUID) -> Unit, modifier: Modifier = Modifier, ) { - LazyColumn( - modifier = modifier.fillMaxWidth() - ) { + LazyColumn(modifier = modifier.fillMaxWidth()) { items( items = notifications, - key = { item -> item.id } - ) {notification -> + key = { item -> item.id }, + ) { notification -> NotificationItem( notification = notification, onNotificationClick = onNotificationClick, @@ -181,13 +182,11 @@ internal fun NotificationItems( @Composable private fun NoticeItems( - notices: ImmutableList, - onNotificationDetailClick: (UUID, UUID) -> Unit, + notices: ImmutableList, + onNotificationDetailClick: (UUID) -> Unit, modifier: Modifier = Modifier, ) { - LazyColumn( - modifier = modifier.fillMaxSize(), - ) { + LazyColumn(modifier = modifier.fillMaxSize()) { items( items = notices, key = { item -> item.id }, @@ -209,24 +208,33 @@ internal fun NotificationItem( Row( modifier = modifier .fillMaxWidth() - .clickable(onClick = { onNotificationClick(notification.pointDetailTopic, notification.id) }) + .clickable( + onClick = { + onNotificationClick( + notification.pointDetailTopic, + notification.id, + ) + }, + ) .padding(horizontal = 24.dp, vertical = 20.dp), verticalAlignment = Alignment.CenterVertically, ) { Image( - painter = painterResource(if (notification.pointDetailTopic == PointType.MINUS) DmsIcon.Minus else DmsIcon.Plus), + painter = painterResource( + if (notification.pointDetailTopic == PointType.MINUS) { + DmsIcon.Minus + } else { + DmsIcon.Plus + }, + ), contentDescription = null, ) - Column( - modifier = Modifier.startPadding(12.dp), - ) { + Column(modifier = Modifier.startPadding(12.dp)) { Text( text = notification.title, style = DmsTheme.typography.bodyM, ) - Row( - modifier = Modifier.topPadding(6.dp) - ) { + Row(modifier = Modifier.topPadding(6.dp)) { if (!notification.isRead) { Icon( modifier = Modifier.size(4.dp), @@ -236,8 +244,7 @@ internal fun NotificationItem( ) } Text( - modifier = Modifier - .startPadding(4.dp), + modifier = Modifier.startPadding(4.dp), text = notification.content, style = DmsTheme.typography.labelM, ) From 03f59df4e9e332f2c8d05ddd24d2d9f45cd5fc4e Mon Sep 17 00:00:00 2001 From: ashxom Date: Wed, 22 Jul 2026 16:43:10 +0900 Subject: [PATCH 3/4] =?UTF-8?q?refactor=20::=20=EA=B3=B5=EC=A7=80=20?= =?UTF-8?q?=EB=AA=A9=EB=A1=9D=20=ED=95=AD=EB=AA=A9=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EB=AF=B8=EC=A7=80=EC=9B=90=20=EB=A9=94=ED=83=80=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../notification/ui/component/NoticeItem.kt | 46 ++++--------------- 1 file changed, 9 insertions(+), 37 deletions(-) diff --git a/feature/src/main/kotlin/team/aliens/dms/android/feature/notification/ui/component/NoticeItem.kt b/feature/src/main/kotlin/team/aliens/dms/android/feature/notification/ui/component/NoticeItem.kt index 2e8f86f1e..fa23d73c8 100644 --- a/feature/src/main/kotlin/team/aliens/dms/android/feature/notification/ui/component/NoticeItem.kt +++ b/feature/src/main/kotlin/team/aliens/dms/android/feature/notification/ui/component/NoticeItem.kt @@ -5,9 +5,6 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Circle import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -18,26 +15,22 @@ import androidx.compose.ui.unit.dp import team.aliens.dms.android.core.designsystem.DmsTheme import team.aliens.dms.android.core.designsystem.bodyM import team.aliens.dms.android.core.designsystem.foundation.DmsIcon -import team.aliens.dms.android.core.designsystem.labelM import team.aliens.dms.android.core.designsystem.startPadding -import team.aliens.dms.android.core.designsystem.topPadding import team.aliens.dms.android.core.designsystem.util.clickable -import team.aliens.dms.android.feature.notification.viewmodel.NotificationUi +import team.aliens.dms.android.feature.notification.viewmodel.NoticeUi import java.util.UUID @Composable internal fun NoticeItem( - notice: NotificationUi, - onNotificationDetailClick: (UUID, UUID) -> Unit, + notice: NoticeUi, + onNotificationDetailClick: (UUID) -> Unit, modifier: Modifier = Modifier, ) { - Column( - modifier = modifier - ) { + Column(modifier = modifier) { Row( modifier = Modifier .fillMaxWidth() - .clickable(onClick = { onNotificationDetailClick(notice.linkId, notice.id) }) + .clickable(onClick = { onNotificationDetailClick(notice.id) }) .padding(horizontal = 24.dp, vertical = 22.dp), verticalAlignment = Alignment.CenterVertically, ) { @@ -46,32 +39,11 @@ internal fun NoticeItem( tint = DmsTheme.colorScheme.scrim, contentDescription = null, ) - Column( + Text( modifier = Modifier.startPadding(12.dp), - ) { - Text( - text = notice.title, - style = DmsTheme.typography.bodyM, - ) - Row( - modifier = Modifier.topPadding(6.dp) - ) { - if (!notice.isRead) { - Icon( - modifier = Modifier.size(4.dp), - imageVector = Icons.Filled.Circle, - contentDescription = null, - tint = DmsTheme.colorScheme.primaryContainer, - ) - } - Text( - modifier = Modifier - .startPadding(4.dp), - text = notice.content, - style = DmsTheme.typography.labelM, - ) - } - } + text = notice.title, + style = DmsTheme.typography.bodyM, + ) Spacer(modifier = Modifier.weight(1f)) Text( modifier = Modifier.padding(horizontal = 10.dp), From 5244051c342592ccfcd3167bc4bc16c58444166b Mon Sep 17 00:00:00 2001 From: ashxom Date: Wed, 22 Jul 2026 16:59:40 +0900 Subject: [PATCH 4/4] =?UTF-8?q?fix=20::=20=EA=B3=B5=EC=A7=80=20=EC=99=B8?= =?UTF-8?q?=20=EC=95=8C=EB=A6=BC=EC=9D=B4=20=EB=88=84=EB=9D=BD=EB=90=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8F=84=EB=A1=9D=20=EC=95=8C=EB=A6=BC=20?= =?UTF-8?q?=ED=95=84=ED=84=B0=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/notification/viewmodel/NotificationViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feature/src/main/kotlin/team/aliens/dms/android/feature/notification/viewmodel/NotificationViewModel.kt b/feature/src/main/kotlin/team/aliens/dms/android/feature/notification/viewmodel/NotificationViewModel.kt index 8263d5a83..eda6497ae 100644 --- a/feature/src/main/kotlin/team/aliens/dms/android/feature/notification/viewmodel/NotificationViewModel.kt +++ b/feature/src/main/kotlin/team/aliens/dms/android/feature/notification/viewmodel/NotificationViewModel.kt @@ -33,7 +33,7 @@ internal class NotificationViewModel @Inject constructor( notificationRepository.fetchNotifications() .onSuccess { notifications -> val notificationsUi = notifications - .filter { notification -> notification.topic == NotificationTopic.POINT } + .filter { notification -> notification.topic != NotificationTopic.NOTICE } .map { notification -> NotificationUi( id = notification.id,