Skip to content

Commit

Permalink
๐Ÿ’ก FCM ํžˆ์Šคํ† ๋ฆฌ ์กฐํšŒ ๊ธฐ๋Šฅ (#108)
Browse files Browse the repository at this point in the history
* [feat] ์•Œ๋ฆผ ํŽ˜์ด์ง€ view

* [feat] ์•Œ๋ฆผ ํŽ˜์ด์ง€ api ์ž‘์—…
  • Loading branch information
HamBeomJoon authored Aug 15, 2024
1 parent 404a8b4 commit 1a3b434
Show file tree
Hide file tree
Showing 19 changed files with 348 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,14 @@ package com.nabi.data.datasource
import com.nabi.data.model.BaseResponse
import com.nabi.data.model.notification.FcmRequestDTO
import com.nabi.data.model.notification.FcmResponseDTO
import com.nabi.data.model.notification.NotificationResponseDTO

interface NotificationRemoteDataSource {

suspend fun getNotification(
accessToken: String
): Result<BaseResponse<NotificationResponseDTO>>

suspend fun registerFcmToken(
accessToken: String,
body: FcmRequestDTO
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,39 @@ import com.nabi.data.datasource.NotificationRemoteDataSource
import com.nabi.data.model.BaseResponse
import com.nabi.data.model.notification.FcmRequestDTO
import com.nabi.data.model.notification.FcmResponseDTO
import com.nabi.data.model.notification.NotificationResponseDTO
import com.nabi.data.service.NotificationService
import javax.inject.Inject

class NotificationRemoteDataSourceImpl @Inject constructor(
private val notificationService: NotificationService
) : NotificationRemoteDataSource {
override suspend fun getNotification(accessToken: String): Result<BaseResponse<NotificationResponseDTO>> {
return try {
val response = notificationService.getNotification(accessToken)

if (response.isSuccessful) {
val notifyResponse = response.body()
if (notifyResponse != null) {
Result.success(notifyResponse)
} else {
Result.failure(Exception("Get Notification fail: response body is null"))
}
} else {
Result.failure(Exception("Get Notification fail: ${response.message()}"))
}
} catch (e: Exception) {
Result.failure(e)
}
}

override suspend fun registerFcmToken(
accessToken: String,
body: FcmRequestDTO
): Result<BaseResponse<FcmResponseDTO>> {
return try {
val response = notificationService.registerFcmToken(accessToken, body)

if (response.isSuccessful) {
val fcmResponse = response.body()
if (fcmResponse != null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.nabi.data.model.notification


import com.google.gson.annotations.SerializedName

class NotificationResponseDTO : ArrayList<NotificationResponseDTOItem>()
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.nabi.data.model.notification


import com.google.gson.annotations.SerializedName

data class NotificationResponseDTOItem(
@SerializedName("body")
val body: String,
@SerializedName("createdAt")
val createdAt: String,
@SerializedName("title")
val title: String
)
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,30 @@ import javax.inject.Inject
class NotificationRepositoryImpl @Inject constructor(
private val notificationRemoteDataSource: NotificationRemoteDataSource
) : NotificationRepository {
override suspend fun getNotification(accessToken: String): Result<List<String>> {
val result = notificationRemoteDataSource.getNotification(accessToken)

return if (result.isSuccess) {
val res = result.getOrNull()
if (res != null) {
val data = res.data
if (data != null) {
val notifyList = mutableListOf<String>()
for (item in data) {
notifyList.add(item.body)
}
Result.success(notifyList)
} else {
Result.failure(Exception("Get Notification failed: data is null"))
}
} else {
Result.failure(Exception("Get Notification failed: response body is null"))
}
} else {
Result.failure(result.exceptionOrNull() ?: Exception("Unknown error"))
}
}

override suspend fun registerFcmToken(accessToken: String, fcmToken: String): Result<String> {
val result = notificationRemoteDataSource.registerFcmToken(accessToken, FcmRequestDTO(fcmToken))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,20 @@ package com.nabi.data.service
import com.nabi.data.model.BaseResponse
import com.nabi.data.model.notification.FcmRequestDTO
import com.nabi.data.model.notification.FcmResponseDTO
import com.nabi.data.model.notification.NotificationResponseDTO
import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.POST

interface NotificationService {

@GET("/fcm/notification")
suspend fun getNotification(
@Header("Authorization") accessToken: String
): Response<BaseResponse<NotificationResponseDTO>>

@POST("/fcm/register")
suspend fun registerFcmToken(
@Header("Authorization") accessToken: String,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.nabi.domain.model.notification

data class NotificationInfo(
val contents: String
)
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.nabi.domain.repository

interface NotificationRepository {

suspend fun getNotification(accessToken: String): Result<List<String>>

suspend fun registerFcmToken(accessToken: String, fcmToken: String): Result<String>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.nabi.domain.usecase.notification

import com.nabi.domain.repository.NotificationRepository

class GetNotificationUseCase(private val repository: NotificationRepository) {
suspend operator fun invoke(accessToken: String): Result<List<String>> {
return repository.getNotification("Bearer $accessToken")
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.nabi.nabi.di

import com.nabi.domain.repository.NotificationRepository
import com.nabi.domain.usecase.notification.GetNotificationUseCase
import com.nabi.domain.usecase.notification.RegisterFcmTokenUseCase
import dagger.Module
import dagger.Provides
Expand All @@ -12,6 +13,14 @@ import javax.inject.Singleton
@InstallIn(SingletonComponent::class)
object NotificationUseCaseModule {

@Provides
@Singleton
fun provideGetNotificationUseCase(
repository: NotificationRepository
): GetNotificationUseCase {
return GetNotificationUseCase(repository = repository)
}

@Provides
@Singleton
fun provideRegisterFcmTokenUseCase(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import com.nabi.nabi.views.chat.ChatFragment
import com.nabi.nabi.views.diary.add.AddDiarySelectDateFragment
import com.nabi.nabi.views.diary.detail.DetailDiaryFragment
import com.nabi.nabi.views.diary.view.SelectDiaryFragment
import com.nabi.nabi.views.notification.NotifyFragment
import com.nabi.nabi.views.myPage.MyPageFragment
import dagger.hilt.android.AndroidEntryPoint

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.nabi.nabi.views.notification

import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.nabi.nabi.databinding.ItemFcmNotifyBinding

class NotificationAdapter : RecyclerView.Adapter<NotificationAdapter.ActivityViewHolder>() {
private var notifyList: List<String> = mutableListOf()

inner class ActivityViewHolder(val binding: ItemFcmNotifyBinding) :
RecyclerView.ViewHolder(binding.root) {

fun bind(content: String) {
binding.tvFcmContent.text = content
}
}

override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): ActivityViewHolder {
val binding =
ItemFcmNotifyBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ActivityViewHolder(binding)
}

override fun onBindViewHolder(holder: ActivityViewHolder, position: Int) {
holder.bind(notifyList[position])
}

override fun getItemCount(): Int = notifyList.size

@SuppressLint("NotifyDataSetChanged")
fun setData(newList: List<String>) {
notifyList = newList
notifyDataSetChanged()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.nabi.nabi.views.notification

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.nabi.domain.usecase.datastore.GetAccessTokenUseCase
import com.nabi.domain.usecase.notification.GetNotificationUseCase
import com.nabi.nabi.utils.UiState
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class NotificationViewModel @Inject constructor(
private val getNotificationUseCase: GetNotificationUseCase,
private val getAccessTokenUseCase: GetAccessTokenUseCase
) : ViewModel() {

private val _notifyState = MutableLiveData<UiState<List<String>>>(UiState.Loading)
val notifyState: LiveData<UiState<List<String>>> get() = _notifyState

fun fetchData() {
_notifyState.value = UiState.Loading

viewModelScope.launch {
val accessTokenResult = getAccessTokenUseCase.invoke()

if (accessTokenResult.isSuccess) {
val accessToken = accessTokenResult.getOrNull().orEmpty()

getNotificationUseCase(accessToken).onSuccess {
_notifyState.value = UiState.Success(it)
}.onFailure { e ->
_notifyState.value = UiState.Failure(message = e.message.toString())
}
} else {
_notifyState.value = UiState.Failure(message = "Failed to get Notification List")
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.nabi.nabi.views.notification

import androidx.core.content.ContextCompat
import androidx.fragment.app.viewModels
import androidx.recyclerview.widget.LinearLayoutManager
import com.nabi.nabi.R
import com.nabi.nabi.base.BaseFragment
import com.nabi.nabi.custom.CustomDecoration
import com.nabi.nabi.databinding.FragmentNotifyBinding
import com.nabi.nabi.utils.LoggerUtils
import com.nabi.nabi.utils.UiState
import com.nabi.nabi.views.MainActivity
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class NotifyFragment : BaseFragment<FragmentNotifyBinding>(R.layout.fragment_notify) {
private lateinit var notificationAdapter: NotificationAdapter
private val viewModel: NotificationViewModel by viewModels()

override fun initView() {
(requireActivity() as MainActivity).setStatusBarColor(R.color.white, false)

viewModel.fetchData()
setNotificationRv()
}

private fun setNotificationRv() {
notificationAdapter = NotificationAdapter()

binding.rvFcmNotify.apply {
adapter = notificationAdapter
layoutManager =
LinearLayoutManager(requireContext())
addItemDecoration(
CustomDecoration(
0.5f,
ContextCompat.getColor(requireContext(), R.color.gray2)
)
)
}
}

override fun setObserver() {
super.setObserver()

viewModel.notifyState.observe(this) {
when (it) {
is UiState.Loading -> {}
is UiState.Failure -> {
showToast(it.message)
LoggerUtils.e("์•Œ๋ฆผ ๋ฐ์ดํ„ฐ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ ์‹คํŒจ: ${it.message}")
}

is UiState.Success -> {
notificationAdapter.setData(it.data)
}
}
}
}
}
Loading

0 comments on commit 1a3b434

Please sign in to comment.