diff --git a/Nabi/data/src/main/java/com/nabi/data/datasource/NotificationRemoteDataSource.kt b/Nabi/data/src/main/java/com/nabi/data/datasource/NotificationRemoteDataSource.kt index 356bb97..eb5e86f 100644 --- a/Nabi/data/src/main/java/com/nabi/data/datasource/NotificationRemoteDataSource.kt +++ b/Nabi/data/src/main/java/com/nabi/data/datasource/NotificationRemoteDataSource.kt @@ -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> + suspend fun registerFcmToken( accessToken: String, body: FcmRequestDTO diff --git a/Nabi/data/src/main/java/com/nabi/data/datasourceImpl/NotificationRemoteDataSourceImpl.kt b/Nabi/data/src/main/java/com/nabi/data/datasourceImpl/NotificationRemoteDataSourceImpl.kt index 2c81d7b..c2e7114 100644 --- a/Nabi/data/src/main/java/com/nabi/data/datasourceImpl/NotificationRemoteDataSourceImpl.kt +++ b/Nabi/data/src/main/java/com/nabi/data/datasourceImpl/NotificationRemoteDataSourceImpl.kt @@ -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> { + 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> { return try { val response = notificationService.registerFcmToken(accessToken, body) + if (response.isSuccessful) { val fcmResponse = response.body() if (fcmResponse != null) { diff --git a/Nabi/data/src/main/java/com/nabi/data/model/notification/NotificationResponseDTO.kt b/Nabi/data/src/main/java/com/nabi/data/model/notification/NotificationResponseDTO.kt new file mode 100644 index 0000000..b5028c2 --- /dev/null +++ b/Nabi/data/src/main/java/com/nabi/data/model/notification/NotificationResponseDTO.kt @@ -0,0 +1,6 @@ +package com.nabi.data.model.notification + + +import com.google.gson.annotations.SerializedName + +class NotificationResponseDTO : ArrayList() \ No newline at end of file diff --git a/Nabi/data/src/main/java/com/nabi/data/model/notification/NotificationResponseDTOItem.kt b/Nabi/data/src/main/java/com/nabi/data/model/notification/NotificationResponseDTOItem.kt new file mode 100644 index 0000000..f1bb2ae --- /dev/null +++ b/Nabi/data/src/main/java/com/nabi/data/model/notification/NotificationResponseDTOItem.kt @@ -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 +) \ No newline at end of file diff --git a/Nabi/data/src/main/java/com/nabi/data/repository/NotificationRepositoryImpl.kt b/Nabi/data/src/main/java/com/nabi/data/repository/NotificationRepositoryImpl.kt index 5db84ce..61af9d4 100644 --- a/Nabi/data/src/main/java/com/nabi/data/repository/NotificationRepositoryImpl.kt +++ b/Nabi/data/src/main/java/com/nabi/data/repository/NotificationRepositoryImpl.kt @@ -8,6 +8,30 @@ import javax.inject.Inject class NotificationRepositoryImpl @Inject constructor( private val notificationRemoteDataSource: NotificationRemoteDataSource ) : NotificationRepository { + override suspend fun getNotification(accessToken: String): Result> { + 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() + 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 { val result = notificationRemoteDataSource.registerFcmToken(accessToken, FcmRequestDTO(fcmToken)) diff --git a/Nabi/data/src/main/java/com/nabi/data/service/NotificationService.kt b/Nabi/data/src/main/java/com/nabi/data/service/NotificationService.kt index d361b93..baec06c 100644 --- a/Nabi/data/src/main/java/com/nabi/data/service/NotificationService.kt +++ b/Nabi/data/src/main/java/com/nabi/data/service/NotificationService.kt @@ -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> + @POST("/fcm/register") suspend fun registerFcmToken( @Header("Authorization") accessToken: String, diff --git a/Nabi/domain/src/main/java/com/nabi/domain/model/notification/NotificationInfo.kt b/Nabi/domain/src/main/java/com/nabi/domain/model/notification/NotificationInfo.kt new file mode 100644 index 0000000..e10d47f --- /dev/null +++ b/Nabi/domain/src/main/java/com/nabi/domain/model/notification/NotificationInfo.kt @@ -0,0 +1,5 @@ +package com.nabi.domain.model.notification + +data class NotificationInfo( + val contents: String +) diff --git a/Nabi/domain/src/main/java/com/nabi/domain/repository/NotificationRepository.kt b/Nabi/domain/src/main/java/com/nabi/domain/repository/NotificationRepository.kt index def9c60..d99d278 100644 --- a/Nabi/domain/src/main/java/com/nabi/domain/repository/NotificationRepository.kt +++ b/Nabi/domain/src/main/java/com/nabi/domain/repository/NotificationRepository.kt @@ -1,5 +1,8 @@ package com.nabi.domain.repository interface NotificationRepository { + + suspend fun getNotification(accessToken: String): Result> + suspend fun registerFcmToken(accessToken: String, fcmToken: String): Result } \ No newline at end of file diff --git a/Nabi/domain/src/main/java/com/nabi/domain/usecase/notification/GetNotificationUseCase.kt b/Nabi/domain/src/main/java/com/nabi/domain/usecase/notification/GetNotificationUseCase.kt new file mode 100644 index 0000000..077113d --- /dev/null +++ b/Nabi/domain/src/main/java/com/nabi/domain/usecase/notification/GetNotificationUseCase.kt @@ -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> { + return repository.getNotification("Bearer $accessToken") + } +} \ No newline at end of file diff --git a/Nabi/presentation/src/main/java/com/nabi/nabi/di/NotificationUseCaseModule.kt b/Nabi/presentation/src/main/java/com/nabi/nabi/di/NotificationUseCaseModule.kt index 43e2f1f..3127b3d 100644 --- a/Nabi/presentation/src/main/java/com/nabi/nabi/di/NotificationUseCaseModule.kt +++ b/Nabi/presentation/src/main/java/com/nabi/nabi/di/NotificationUseCaseModule.kt @@ -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 @@ -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( diff --git a/Nabi/presentation/src/main/java/com/nabi/nabi/views/home/HomeFragment.kt b/Nabi/presentation/src/main/java/com/nabi/nabi/views/home/HomeFragment.kt index 27ef83b..beed4be 100644 --- a/Nabi/presentation/src/main/java/com/nabi/nabi/views/home/HomeFragment.kt +++ b/Nabi/presentation/src/main/java/com/nabi/nabi/views/home/HomeFragment.kt @@ -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 diff --git a/Nabi/presentation/src/main/java/com/nabi/nabi/views/home/NotifyFragment.kt b/Nabi/presentation/src/main/java/com/nabi/nabi/views/home/NotifyFragment.kt deleted file mode 100644 index df4c7ff..0000000 --- a/Nabi/presentation/src/main/java/com/nabi/nabi/views/home/NotifyFragment.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.nabi.nabi.views.home - -import com.nabi.nabi.R -import com.nabi.nabi.base.BaseFragment -import com.nabi.nabi.databinding.FragmentMypageBinding - -class NotifyFragment: BaseFragment(R.layout.fragment_mypage) { - override fun initView() { - TODO("Not yet implemented") - } - -} \ No newline at end of file diff --git a/Nabi/presentation/src/main/java/com/nabi/nabi/views/notification/NotificationAdapter.kt b/Nabi/presentation/src/main/java/com/nabi/nabi/views/notification/NotificationAdapter.kt new file mode 100644 index 0000000..a890998 --- /dev/null +++ b/Nabi/presentation/src/main/java/com/nabi/nabi/views/notification/NotificationAdapter.kt @@ -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() { + private var notifyList: List = 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) { + notifyList = newList + notifyDataSetChanged() + } +} \ No newline at end of file diff --git a/Nabi/presentation/src/main/java/com/nabi/nabi/views/notification/NotificationViewModel.kt b/Nabi/presentation/src/main/java/com/nabi/nabi/views/notification/NotificationViewModel.kt new file mode 100644 index 0000000..56d426a --- /dev/null +++ b/Nabi/presentation/src/main/java/com/nabi/nabi/views/notification/NotificationViewModel.kt @@ -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.Loading) + val notifyState: LiveData>> 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") + } + } + } +} \ No newline at end of file diff --git a/Nabi/presentation/src/main/java/com/nabi/nabi/views/notification/NotifyFragment.kt b/Nabi/presentation/src/main/java/com/nabi/nabi/views/notification/NotifyFragment.kt new file mode 100644 index 0000000..c6fe96f --- /dev/null +++ b/Nabi/presentation/src/main/java/com/nabi/nabi/views/notification/NotifyFragment.kt @@ -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(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) + } + } + } + } +} \ No newline at end of file diff --git a/Nabi/presentation/src/main/res/layout/fragment_notify.xml b/Nabi/presentation/src/main/res/layout/fragment_notify.xml new file mode 100644 index 0000000..90840eb --- /dev/null +++ b/Nabi/presentation/src/main/res/layout/fragment_notify.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Nabi/presentation/src/main/res/layout/item_fcm_notify.xml b/Nabi/presentation/src/main/res/layout/item_fcm_notify.xml new file mode 100644 index 0000000..f9e5065 --- /dev/null +++ b/Nabi/presentation/src/main/res/layout/item_fcm_notify.xml @@ -0,0 +1,35 @@ + + + + + + + + \ No newline at end of file diff --git a/Nabi/presentation/src/main/res/values/font_style.xml b/Nabi/presentation/src/main/res/values/font_style.xml index f7f1b29..bb97eda 100644 --- a/Nabi/presentation/src/main/res/values/font_style.xml +++ b/Nabi/presentation/src/main/res/values/font_style.xml @@ -175,4 +175,18 @@ 12sp 15sp + + + + \ No newline at end of file diff --git a/Nabi/presentation/src/main/res/values/strings.xml b/Nabi/presentation/src/main/res/values/strings.xml index 974906e..dfdd7bc 100644 --- a/Nabi/presentation/src/main/res/values/strings.xml +++ b/Nabi/presentation/src/main/res/values/strings.xml @@ -62,4 +62,7 @@ 회원 탈퇴 제작자 이메일\nmjusw2024@gmail.com + + 알림 + \ No newline at end of file