Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

알림 권한 근거 다이얼로그 구현 #138

Open
wants to merge 9 commits into
base: feature/fcm
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ class StudyRepository {
studyService.addRegistrationId(sid, mapOf(registrationId to true))
}

suspend fun getRegistrationIdList(sid: String): Map<String, Boolean> {
return studyService.getRegistrationIdList(sid)
}

fun getMessageList(sid: String): Flow<Map<String, Message>> = flow {
while (true) {
kotlin.runCatching {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,11 @@ interface StudyService {
@Body registrationId: Map<String, Boolean>
)

@GET("studies/{sid}/registrationIds.json")
suspend fun getRegistrationIdList(
@Path("sid") sid: String
): Map<String, Boolean>

companion object {
private const val BASE_URL = BuildConfig.FIREBASE_BASE_URL
private val contentType = "application/json".toMediaType()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package com.sesac.developer_study_platform.ui.common

import android.Manifest
import android.os.Build
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import com.sesac.developer_study_platform.EventObserver
import com.sesac.developer_study_platform.R
import com.sesac.developer_study_platform.data.source.local.FcmTokenRepository
import com.sesac.developer_study_platform.databinding.DialogNotificationPermissionBinding

class NotificationPermissionDialogFragment : DialogFragment() {

private var _binding: DialogNotificationPermissionBinding? = null
private val binding get() = _binding!!
private val viewModel by viewModels<NotificationPermissionDialogViewModel> {
NotificationPermissionDialogViewModel.create(FcmTokenRepository(requireContext()))
}
private val args by navArgs<NotificationPermissionDialogFragmentArgs>()
private val requestPermissionLauncher =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
if (isGranted) {
checkNotificationKey()
} else {
Toast.makeText(context, getString(R.string.all_notification_info), Toast.LENGTH_SHORT).show()
viewModel.moveToMessage(args.studyId)
}
}

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = DialogNotificationPermissionBinding.inflate(inflater, container, false)
return binding.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

setYesButton()
binding.btnNo.setOnClickListener {
viewModel.moveToMessage(args.studyId)
}
setNavigation()
}

private fun setYesButton() {
binding.btnYes.setOnClickListener {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
} else {
checkNotificationKey()
}
}
}

private fun checkNotificationKey() {
viewModel.checkNotificationKey(args.studyId)
viewModel.checkNotificationKeyEvent.observe(
viewLifecycleOwner,
EventObserver {
viewModel.moveToMessage(args.studyId)
}
)
}

private fun setNavigation() {
viewModel.moveToMessageEvent.observe(
viewLifecycleOwner,
EventObserver {
val action = NotificationPermissionDialogFragmentDirections.actionGlobalToMessage(it)
findNavController().navigate(action)
}
)
}

override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
package com.sesac.developer_study_platform.ui.common

import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
import com.sesac.developer_study_platform.Event
import com.sesac.developer_study_platform.StudyApplication.Companion.fcmRepository
import com.sesac.developer_study_platform.StudyApplication.Companion.studyRepository
import com.sesac.developer_study_platform.data.StudyGroup
import com.sesac.developer_study_platform.data.source.local.FcmTokenRepository
import kotlinx.coroutines.async
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch

class NotificationPermissionDialogViewModel(private val fcmTokenRepository: FcmTokenRepository) :
ViewModel() {

private val _checkNotificationKeyEvent: MutableLiveData<Event<Unit>> = MutableLiveData()
val checkNotificationKeyEvent: LiveData<Event<Unit>> = _checkNotificationKeyEvent

private val _moveToMessageEvent: MutableLiveData<Event<String>> = MutableLiveData()
val moveToMessageEvent: LiveData<Event<String>> = _moveToMessageEvent

fun checkNotificationKey(sid: String) {
viewModelScope.launch {
if (getNotificationKey(sid).isNullOrEmpty()) {
createNotificationKey(sid)
} else if (isRegistrationId(sid, fcmTokenRepository.getToken().first())) {
updateStudyGroup(sid)
}
}
}

private fun createNotificationKey(sid: String) {
viewModelScope.launch {
val token = fcmTokenRepository.getToken().first()
kotlin.runCatching {
fcmRepository.updateStudyGroup(StudyGroup("create", sid, listOf(token)))
}.onSuccess {
addNotificationKey(sid, it.values.first())
}.onFailure {
Log.e(
"NotificationPermissionDialogViewModel-createNotificationKey",
it.message ?: "error occurred."
)
}
}
}

private fun addNotificationKey(sid: String, notificationKey: String) {
viewModelScope.launch {
kotlin.runCatching {
studyRepository.addNotificationKey(sid, notificationKey)
}.onSuccess {
addRegistrationId(sid, fcmTokenRepository.getToken().first())
}.onFailure {
Log.e(
"NotificationPermissionDialogViewModel-addNotificationKey",
it.message ?: "error occurred."
)
}
}
}

private fun updateStudyGroup(sid: String) {
viewModelScope.launch {
val token = fcmTokenRepository.getToken().first()
kotlin.runCatching {
val notificationKey = getNotificationKey(sid)
if (!notificationKey.isNullOrEmpty()) {
fcmRepository.updateStudyGroup(StudyGroup("add", sid, listOf(token), notificationKey))
}
}.onSuccess {
addRegistrationId(sid, token)
}.onFailure {
Log.e(
"NotificationPermissionDialogViewModel-updateStudyGroup",
it.message ?: "error occurred."
)
}
}
}

private suspend fun getNotificationKey(sid: String): String? {
return viewModelScope.async {
kotlin.runCatching {
studyRepository.getNotificationKey(sid)
}.onFailure {
Log.e(
"NotificationPermissionDialogViewModel-getNotificationKey",
it.message ?: "error occurred."
)
}.getOrNull()
}.await()
}

private fun addRegistrationId(sid: String, registrationId: String) {
viewModelScope.launch {
kotlin.runCatching {
studyRepository.addRegistrationId(sid, registrationId)
}.onSuccess {
_checkNotificationKeyEvent.value = Event(Unit)
}.onFailure {
Log.e(
"NotificationPermissionDialogViewModel-addRegistrationId",
it.message ?: "error occurred."
)
}
}
}

private suspend fun isRegistrationId(sid: String, registrationId: String): Boolean {
return viewModelScope.async {
kotlin.runCatching {
studyRepository.getRegistrationIdList(sid)
}.map {
it.containsKey(registrationId)
}.onFailure {
Log.e(
"NotificationPermissionDialogViewModel-isRegistrationId",
it.message ?: "error occurred."
)
}.getOrDefault(false)
}.await()
}

fun moveToMessage(sid: String) {
_moveToMessageEvent.value = Event(sid)
}

companion object {
fun create(fcmTokenRepository: FcmTokenRepository) = viewModelFactory {
initializer {
NotificationPermissionDialogViewModel(fcmTokenRepository)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.content.ContextCompat
Expand Down Expand Up @@ -51,24 +50,13 @@ class JoinStudyDialogFragment : DialogFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

setDialog()
setNavigation()
setYesButton()
binding.btnNo.setOnClickListener {
dismiss()
}
}

private fun setDialog() {
val displayMetrics = resources.displayMetrics
val widthPixels = displayMetrics.widthPixels

val params = dialog?.window?.attributes
params?.width = (widthPixels * 0.9).toInt()
dialog?.window?.attributes = params as WindowManager.LayoutParams
dialog?.window?.setBackgroundDrawableResource(R.drawable.bg_white_radius_18dp)
}

private fun setYesButton() {
binding.btnYes.setOnClickListener {
viewModel.addUserStudy(
Expand All @@ -87,6 +75,11 @@ class JoinStudyDialogFragment : DialogFragment() {
}

private fun setNavigation() {
moveToMessage()
moveToNotificationPermissionDialog()
}

private fun moveToMessage() {
viewModel.moveToMessageEvent.observe(
viewLifecycleOwner,
EventObserver {
Expand All @@ -96,6 +89,16 @@ class JoinStudyDialogFragment : DialogFragment() {
)
}

private fun moveToNotificationPermissionDialog() {
viewModel.moveToNotificationPermissionDialogEvent.observe(
viewLifecycleOwner,
EventObserver {
val action = JoinStudyDialogFragmentDirections.actionGlobalToNotificationPermissionDialog(it)
findNavController().navigate(action)
}
)
}

private fun askNotificationPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
when {
Expand All @@ -107,7 +110,7 @@ class JoinStudyDialogFragment : DialogFragment() {
}

shouldShowRequestPermissionRationale(Manifest.permission.POST_NOTIFICATIONS) -> {
// TODO 권한 이유 다이얼로그
viewModel.moveToNotificationPermissionDialog(args.study.sid)
}

else -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ class JoinStudyDialogViewModel(private val fcmTokenRepository: FcmTokenRepositor
private val _moveToMessageEvent: MutableLiveData<Event<String>> = MutableLiveData()
val moveToMessageEvent: LiveData<Event<String>> = _moveToMessageEvent

private val _moveToNotificationPermissionDialogEvent: MutableLiveData<Event<String>> = MutableLiveData()
val moveToNotificationPermissionDialogEvent: LiveData<Event<String>> =
_moveToNotificationPermissionDialogEvent

fun addUserStudy(sid: String, study: UserStudy) {
viewModelScope.launch {
kotlin.runCatching {
Expand Down Expand Up @@ -102,6 +106,10 @@ class JoinStudyDialogViewModel(private val fcmTokenRepository: FcmTokenRepositor
_moveToMessageEvent.value = Event(sid)
}

fun moveToNotificationPermissionDialog(sid: String) {
_moveToNotificationPermissionDialogEvent.value = Event(sid)
}

companion object {
fun create(fcmTokenRepository: FcmTokenRepository) = viewModelFactory {
initializer {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class MainActivity : AppCompatActivity() {
R.id.dest_exit_dialog -> View.GONE
R.id.dest_ban_dialog -> View.GONE
R.id.dest_join_study_dialog -> View.GONE
R.id.dest_notification_permission_dialog -> View.GONE
else -> View.VISIBLE
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
Expand Down Expand Up @@ -32,7 +31,6 @@ class ExitDialogFragment : DialogFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

setDialog()
setNavigation()
binding.btnNo.setOnClickListener {
dismiss()
Expand All @@ -42,16 +40,6 @@ class ExitDialogFragment : DialogFragment() {
}
}

private fun setDialog() {
val displayMetrics = resources.displayMetrics
val widthPixels = displayMetrics.widthPixels

val params = dialog?.window?.attributes
params?.width = (widthPixels * 0.9).toInt()
dialog?.window?.attributes = params as WindowManager.LayoutParams
dialog?.window?.setBackgroundDrawableResource(R.drawable.bg_white_radius_18dp)
}

private fun setNavigation() {
viewModel.moveToHomeEvent.observe(
viewLifecycleOwner,
Expand Down
Loading