Skip to content

Commit

Permalink
Merge pull request #80 from YAPP-Github/feature/jaino/#75
Browse files Browse the repository at this point in the history
#75 : 알림 탭 화면 구현
  • Loading branch information
jeongjaino authored Aug 9, 2024
2 parents 6424235 + b27c69c commit a7bfe15
Show file tree
Hide file tree
Showing 36 changed files with 546 additions and 31 deletions.
1 change: 1 addition & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ dependencies {
implementation(project(":feature:vote"))
implementation(project(":feature:message"))
implementation(project(":feature:entire"))
implementation(project(":feature:notification"))

implementation(libs.kakao.sdk)
implementation(libs.androidx.appcompat)
Expand Down
13 changes: 13 additions & 0 deletions app/src/main/kotlin/com/bff/wespot/AppNavGraphs.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import com.bff.wespot.message.screen.destinations.MessageWriteScreenDestination
import com.bff.wespot.message.screen.destinations.ReceiverSelectionScreenDestination
import com.bff.wespot.message.screen.destinations.ReservedMessageScreenDestination
import com.bff.wespot.message.viewmodel.SendViewModel
import com.bff.wespot.notification.screen.destinations.NotificationScreenDestination
import com.bff.wespot.navigation.Navigator
import com.bff.wespot.vote.screen.destinations.CharacterSettingScreenDestination
import com.bff.wespot.vote.screen.destinations.IndividualVoteScreenDestination
Expand Down Expand Up @@ -94,6 +95,17 @@ object AppNavGraphs {
.associateBy { it.route }
}

val notification = object : NavGraphSpec {
override val route = "notification"

override val startRoute = NotificationScreenDestination routedIn this

override val destinationsByRoute = listOf<DestinationSpec<*>>(
NotificationScreenDestination,
).routedIn(this)
.associateBy { it.route }
}

val root = object : NavGraphSpec {
override val route = "root"

Expand All @@ -105,6 +117,7 @@ object AppNavGraphs {
vote,
message,
entire,
notification,
)
}
}
Expand Down
4 changes: 4 additions & 0 deletions app/src/main/kotlin/com/bff/wespot/CommonNavGraphNavigator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ import com.bff.wespot.message.screen.send.MessageWriteNavigator
import com.bff.wespot.message.screen.send.MessageWriteScreenArgs
import com.bff.wespot.message.screen.send.ReceiverSelectionNavigator
import com.bff.wespot.message.screen.send.ReceiverSelectionScreenArgs
import com.bff.wespot.notification.screen.NotificationNavigator
import com.bff.wespot.notification.screen.destinations.NotificationScreenDestination
import com.bff.wespot.vote.screen.CharacterSettingNavigator
import com.bff.wespot.vote.screen.IndividualVoteArgs
import com.bff.wespot.vote.screen.IndividualVoteNavigator
Expand Down Expand Up @@ -69,6 +71,7 @@ class CommonNavGraphNavigator(
VoteStorageNavigator,
ReservedMessageNavigator,
IndividualVoteNavigator,
NotificationNavigator,
CharacterSettingNavigator,
IntroductionNavigator {
override fun navigateUp() {
Expand Down Expand Up @@ -100,6 +103,7 @@ class CommonNavGraphNavigator(
}

override fun navigateNotificationScreen() {
navController.navigate(NotificationScreenDestination within navGraph)
}

override fun navigateToResultScreen(args: VoteResultScreenArgs) {
Expand Down
24 changes: 15 additions & 9 deletions app/src/main/kotlin/com/bff/wespot/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,9 @@ private fun MainScreen(navigator: Navigator) {
action = {
IconButton(
modifier = Modifier.padding(top = 10.dp, bottom = 10.dp, end = 4.dp),
onClick = {},
onClick = {
navController.navigateToNavGraph(AppNavGraphs.notification)
},
) {
Icon(
painter = painterResource(id = R.drawable.notification),
Expand All @@ -109,14 +111,7 @@ private fun MainScreen(navigator: Navigator) {
BottomNavigationTab(
selectedNavigation = currentSelectedItem,
onNavigationSelected = { selected ->
navController.navigate(selected) {
launchSingleTop = true
restoreState = true

popUpTo(navController.graph.findStartDestination().id) {
saveState = true
}
}
navController.navigateToNavGraph(selected)
},
modifier = Modifier.fillMaxWidth(),
)
Expand Down Expand Up @@ -239,3 +234,14 @@ private fun TabItem(
}
}
}

private fun NavController.navigateToNavGraph(navGraph: NavGraphSpec) {
this.navigate(navGraph) {
launchSingleTop = true
restoreState = true

popUpTo(this@navigateToNavGraph.graph.findStartDestination().id) {
saveState = true
}
}
}
14 changes: 14 additions & 0 deletions app/src/main/kotlin/com/bff/wespot/PushNotificationService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.bff.wespot

import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage

class PushNotificationService : FirebaseMessagingService() {
override fun onNewToken(token: String) {
super.onNewToken(token)
}

override fun onMessageReceived(message: RemoteMessage) {
super.onMessageReceived(message)
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.bff.wespot.common.util

import java.time.LocalDate
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.time.temporal.ChronoUnit

Expand All @@ -19,6 +20,17 @@ fun String.timeDifference(): Long {
return daysDifference
}

fun LocalDateTime.toDateString(): String {
val currentDateTime = LocalDateTime.now()
val daysBetween = ChronoUnit.DAYS.between(this, currentDateTime)

return when (daysBetween) {
0L -> "오늘"
in 1..7 -> "${daysBetween}일 전"
else -> this.format(DateTimeFormatter.ofPattern("yyyy.MM.dd"))
}
}

fun Long.toDateString(date: String): String =
when (this) {
0L -> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.bff.wespot.model.notification

import java.time.LocalDate
import java.time.LocalDateTime

data class Notification(
val id: Int,
val type: NotificationType,
val date: LocalDate,
val targetId: Int,
val content: String,
val isNew: Boolean,
val isEnable: Boolean,
val createdAt: LocalDateTime,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.bff.wespot.model.notification

enum class NotificationType {
IDLE,
MESSAGE,
MESSAGE_SENT,
MESSAGE_RECEIVED,
VOTE,
VOTE_RESULT,
VOTE_RECEIVED,
;

fun toDescription(): String = when (this) {
MESSAGE, MESSAGE_SENT, MESSAGE_RECEIVED -> "쪽지 알림"
VOTE, VOTE_RESULT, VOTE_RECEIVED -> "투표 알림"
IDLE -> ""
}
}
5 changes: 3 additions & 2 deletions core/ui/src/main/kotlin/com/bff/wespot/ui/RedDot.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,17 @@ import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.bff.wespot.designsystem.theme.WeSpotTheme
import com.bff.wespot.designsystem.theme.WeSpotThemeManager
import com.bff.wespot.designsystem.util.OrientationPreviews

@Composable
fun RedDot(modifier: Modifier = Modifier) {
fun RedDot(modifier: Modifier = Modifier, size: Dp = 6.dp) {
val color = WeSpotThemeManager.colors.dangerColor

Canvas(modifier = modifier.size(6.dp)) {
Canvas(modifier = modifier.size(size)) {
drawCircle(color)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import com.bff.wespot.data.remote.source.message.MessageDataSource
import com.bff.wespot.data.remote.source.message.MessageDataSourceImpl
import com.bff.wespot.data.remote.source.message.MessageStorageDataSource
import com.bff.wespot.data.remote.source.message.MessageStorageDataSourceImpl
import com.bff.wespot.data.remote.source.notification.NotificationDataSource
import com.bff.wespot.data.remote.source.notification.NotificationDataSourceImpl
import com.bff.wespot.data.remote.source.user.UserDataSource
import com.bff.wespot.data.remote.source.user.UserDataSourceImpl
import com.bff.wespot.data.remote.source.vote.VoteDataSource
Expand Down Expand Up @@ -51,6 +53,12 @@ abstract class DataRemoteModule {
messageStorageDataSourceImpl: MessageStorageDataSourceImpl
): MessageStorageDataSource

@Binds
@Singleton
abstract fun bindsNotificationDataSource(
notificationDataSourceImpl: NotificationDataSourceImpl
): NotificationDataSource

@Binds
@Singleton
abstract fun bindsCommonDataSource(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
package com.bff.wespot.data.remote.extensions

import java.time.LocalDate
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter

fun String.toISOLocalDateTime(): LocalDateTime? =
runCatching {
LocalDateTime.parse(this, DateTimeFormatter.ISO_DATE_TIME)
}.recoverCatching {
val correctedString = this.replace(" ", "T")
LocalDateTime.parse(correctedString, DateTimeFormatter.ISO_DATE_TIME)
}.getOrNull()

fun String.toLocalDateFromDashPattern(): LocalDate {
val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd")
return LocalDate.parse(this, formatter)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.bff.wespot.data.remote.model.notification

import com.bff.wespot.data.remote.extensions.toISOLocalDateTime
import com.bff.wespot.data.remote.extensions.toLocalDateFromDashPattern
import com.bff.wespot.model.notification.Notification
import com.bff.wespot.model.notification.NotificationType
import kotlinx.serialization.Serializable
import java.time.LocalDateTime

@Serializable
data class NotificationListDto(
val notifications: List<NotificationDto>
)

@Serializable
data class NotificationDto (
val id: Int,
val type: String,
val date: String,
val targetId: Int,
val content: String,
val isNew: Boolean,
val isEnable: Boolean,
val createdAt: String,
) {
fun toNotification(): Notification = Notification(
id = id,
type = type.convertToNotificationType(),
date = date.toLocalDateFromDashPattern(),
targetId = targetId,
content = content,
isNew = isNew,
isEnable = isEnable,
createdAt = createdAt.toISOLocalDateTime() ?: LocalDateTime.MIN,
)

private fun String.convertToNotificationType(): NotificationType {
return when (this) {
NotificationType.MESSAGE.name -> NotificationType.MESSAGE
NotificationType.MESSAGE_SENT.name -> NotificationType.MESSAGE_SENT
NotificationType.MESSAGE_RECEIVED.name -> NotificationType.MESSAGE_RECEIVED
NotificationType.VOTE.name -> NotificationType.VOTE
NotificationType.VOTE_RESULT.name -> NotificationType.VOTE_RESULT
NotificationType.VOTE_RECEIVED.name -> NotificationType.VOTE_RECEIVED
else -> NotificationType.IDLE
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,5 @@ interface MessageStorageDataSource {

suspend fun blockMessage(messageId: Int): Result<Unit>

suspend fun reportMessage(messageId: Int): Result<Unit>

suspend fun getReservedMessage(): Result<ReservedMessageListDto>
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,6 @@ class MessageStorageDataSourceImpl @Inject constructor(
}
}

override suspend fun reportMessage(messageId: Int): Result<Unit> =
httpClient.safeRequest {
url {
method = HttpMethod.Post
path("messages/$messageId/report")
}
}

override suspend fun getReservedMessage(): Result<ReservedMessageListDto> =
httpClient.safeRequest {
url {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.bff.wespot.data.remote.source.notification

import com.bff.wespot.data.remote.model.notification.NotificationListDto

interface NotificationDataSource {
suspend fun getNotification(): Result<NotificationListDto>

suspend fun updateNotificationReadStatus(id: Int): Result<Unit>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.bff.wespot.data.remote.source.notification

import com.bff.wespot.data.remote.model.notification.NotificationListDto
import com.bff.wespot.network.extensions.safeRequest
import io.ktor.client.HttpClient
import io.ktor.http.HttpMethod
import io.ktor.http.path
import javax.inject.Inject

class NotificationDataSourceImpl @Inject constructor(
private val httpClient: HttpClient,
): NotificationDataSource {
override suspend fun getNotification(): Result<NotificationListDto> =
httpClient.safeRequest {
url {
method = HttpMethod.Get
path("notifications")
}
}

override suspend fun updateNotificationReadStatus(id: Int): Result<Unit> =
httpClient.safeRequest {
url {
method = HttpMethod.Put
path("notifications/$id")
}
}
}
8 changes: 8 additions & 0 deletions data/src/main/kotlin/com/bff/wespot/data/di/DataModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import com.bff.wespot.data.repository.auth.AuthRepositoryImpl
import com.bff.wespot.data.repository.auth.KakaoLoginManagerImpl
import com.bff.wespot.data.repository.message.MessageRepositoryImpl
import com.bff.wespot.data.repository.message.MessageStorageRepositoryImpl
import com.bff.wespot.data.repository.notification.NotificationRepositoryImpl
import com.bff.wespot.data.repository.user.UserRepositoryImpl
import com.bff.wespot.data.repository.vote.VoteRepositoryImpl
import com.bff.wespot.domain.repository.CommonRepository
Expand All @@ -14,6 +15,7 @@ import com.bff.wespot.domain.repository.auth.AuthRepository
import com.bff.wespot.domain.repository.auth.KakaoLoginManager
import com.bff.wespot.domain.repository.message.MessageRepository
import com.bff.wespot.domain.repository.message.MessageStorageRepository
import com.bff.wespot.domain.repository.notification.NotificationRepository
import com.bff.wespot.domain.repository.user.UserRepository
import com.bff.wespot.domain.repository.vote.VoteRepository
import dagger.Binds
Expand Down Expand Up @@ -67,6 +69,12 @@ abstract class DataModule {
messageStorageRepositoryImpl: MessageStorageRepositoryImpl
): MessageStorageRepository

@Binds
@Singleton
abstract fun bindsNotificationRepository(
notificationRepositoryImpl: NotificationRepositoryImpl,
): NotificationRepository

@Binds
@Singleton
abstract fun bindsCommonRepository(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@ class MessageStorageRepositoryImpl @Inject constructor(
override suspend fun blockMessage(messageId: Int): Result<Unit> =
messageStorageDataSource.blockMessage(messageId = messageId)

override suspend fun reportMessage(messageId: Int): Result<Unit> =
messageStorageDataSource.reportMessage(messageId = messageId)

override suspend fun getReservedMessage(): Result<List<Message>> =
messageStorageDataSource.getReservedMessage().mapCatching { list ->
list.messages.map {
Expand Down
Loading

0 comments on commit a7bfe15

Please sign in to comment.