diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e8bcdc28..e95cc344 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -4,6 +4,9 @@ + (R.layout.activity_main private val prevScreenName by lazy { intent.extras?.getString(KEY_PREV_SCREEN, "") } private val notiType by lazy { intent.extras?.getString(KEY_NOTI_TYPE, "") } private val feedId by lazy { intent.extras?.getString(KEY_FEED_ID) } + private val notificationPermissionLauncher = + registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted -> + if (!isGranted) { + wineySnackbar( + anchorView = binding.root, + isSuccess = false, + message = stringOf(R.string.snackbar_notification_permission_fail) + ) + } + } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + requestNotificationPermission() + // 위니피드, 마이페이지 프래그먼트에서 getUserState 관찰 mainViewModel.getUser() mainViewModel.patchFcmToken() @@ -51,6 +68,16 @@ class MainActivity : BindingActivity(R.layout.activity_main showSuccessSnackBar() } + private fun requestNotificationPermission() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && ContextCompat.checkSelfPermission( + this, + Manifest.permission.POST_NOTIFICATIONS + ) == PackageManager.PERMISSION_DENIED + ) { + notificationPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS) + } + } + private fun initNotiTypeHandler() { val notificationType = NotificationType.values().find { it.key == notiType } when (notificationType) { @@ -61,9 +88,11 @@ class MainActivity : BindingActivity(R.layout.activity_main KEY_FROM_NOTI, true ) + NotificationType.LIKE_NOTIFICATION, NotificationType.COMMENT_NOTIFICATION -> navigateToDetail(feedId?.toInt()) - else -> navigateToLevelupHelp() + NotificationType.HOW_TO_LEVEL_UP -> navigateToLevelupHelp() + else -> {} } } diff --git a/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/MyPageFragment.kt b/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/MyPageFragment.kt index ed5253a6..0665653f 100644 --- a/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/MyPageFragment.kt +++ b/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/MyPageFragment.kt @@ -1,10 +1,19 @@ package org.go.sopt.winey.presentation.main.mypage +import android.Manifest +import android.content.ActivityNotFoundException +import android.content.Context import android.content.Intent +import android.content.pm.PackageManager import android.net.Uri +import android.os.Build import android.os.Bundle +import android.provider.Settings import android.view.View import androidx.activity.OnBackPressedCallback +import androidx.core.content.ContextCompat +import androidx.core.view.isGone +import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.fragment.app.commit @@ -34,6 +43,7 @@ import org.go.sopt.winey.util.fragment.snackBar import org.go.sopt.winey.util.fragment.stringOf import org.go.sopt.winey.util.fragment.viewLifeCycle import org.go.sopt.winey.util.fragment.viewLifeCycleScope +import org.go.sopt.winey.util.fragment.wineySnackbar import org.go.sopt.winey.util.view.UiState import org.go.sopt.winey.util.view.setOnSingleClickListener import javax.inject.Inject @@ -48,10 +58,12 @@ class MyPageFragment : BindingFragment(R.layout.fragment_ @Inject lateinit var amplitudeUtils: AmplitudeUtils + private var isNotificationPermissionAllowed = true override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) amplitudeUtils.logEvent("view_mypage") + initCheckNotificationPermission() initUserData() initNavigation() @@ -64,6 +76,7 @@ class MyPageFragment : BindingFragment(R.layout.fragment_ initWithdrawButtonClickListener() initNicknameButtonClickListener() initAllowedNotificationButtonClickListener() + initNotificationPermissionChangeButtonClickListener() registerBackPressedCallback() setupGetUserState() @@ -73,27 +86,36 @@ class MyPageFragment : BindingFragment(R.layout.fragment_ checkFromWineyFeed() } + private fun initCheckNotificationPermission() { + isNotificationPermissionAllowed = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + ContextCompat.checkSelfPermission( + requireContext(), + Manifest.permission.POST_NOTIFICATIONS + ) == PackageManager.PERMISSION_GRANTED + } else { + true + } + } + private fun setupPatchAllowedNotificationState() { myPageViewModel.patchAllowedNotificationState.flowWithLifecycle(lifecycle).onEach { state -> when (state) { is UiState.Success -> { when (state.data) { true -> { - binding.ivMypageAgree.transitionToEnd() + binding.ivMypageAgree.transitionToState(R.id.end, -1) } false -> { - binding.ivMypageAgree.transitionToStart() + binding.ivMypageAgree.transitionToState(R.id.start, -1) } null -> { - binding.ivMypageAgree.transitionToStart() + binding.ivMypageAgree.transitionToState(R.id.start, -1) } } } - is UiState.Failure -> {} - is UiState.Empty -> {} else -> {} } } @@ -101,22 +123,91 @@ class MyPageFragment : BindingFragment(R.layout.fragment_ private fun initAllowedNotificationButtonClickListener() { binding.ivMypageSwitch.setOnClickListener { - val isAllowed = when (binding.ivMypageAgree.currentState) { - R.id.start -> false - R.id.end -> true - else -> false - } - when (isAllowed) { + when (isNotificationPermissionAllowed) { true -> { - binding.ivMypageAgree.transitionToStart() + val isAllowed = when (binding.ivMypageAgree.currentState) { + R.id.start -> false + R.id.end -> true + else -> false + } + when (isAllowed) { + true -> { + showNotificationOffDialog(isAllowed) + } + + false -> { + binding.ivMypageAgree.transitionToState(R.id.end, -1) + patchUserInfo() + myPageViewModel.patchAllowedNotification(isAllowed) + } + } } false -> { - binding.ivMypageAgree.transitionToEnd() + wineySnackbar( + binding.root, + true, + stringOf(R.string.snackbar_notification_permission_fail) + ) } } - patchUserInfo() - myPageViewModel.patchAllowedNotification(isAllowed) + } + } + + private fun showNotificationOffDialog(isAllowed: Boolean) { + val dialog = WineyDialogFragment.newInstance( + WineyDialogLabel( + stringOf(R.string.notification_off_dialog_title), + stringOf(R.string.notification_off_dialog_subtitle), + stringOf(R.string.notification_off_dialog_negative_button), + stringOf(R.string.notification_off_dialog_positive_button) + ), + handleNegativeButton = {}, + handlePositiveButton = { + binding.ivMypageAgree.transitionToState(R.id.start, -1) + patchUserInfo() + myPageViewModel.patchAllowedNotification(isAllowed) + } + ) + dialog.show( + parentFragmentManager, + TAG_NOTIFICATION_OFF_DIALOG + ) + } + + private fun initNotificationPermissionChangeButtonClickListener() { + binding.llMypageAgreePermissionChange.setOnClickListener { + navigateToNotificationSetting(requireContext()) + } + } + + private fun navigateToNotificationSetting(context: Context) { + val intent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + setNotificationIntentActionOreo(context) + } else { + setNorificationIntentActionOreoLess(context) + } + try { + context.startActivity(intent) + } catch (e: ActivityNotFoundException) { + e.printStackTrace() + } + } + + private fun setNotificationIntentActionOreo(context: Context): Intent { + return Intent().also { intent -> + intent.action = Settings.ACTION_APP_NOTIFICATION_SETTINGS + intent.putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName) + intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK + } + } + + private fun setNorificationIntentActionOreoLess(context: Context): Intent { + return Intent().also { intent -> + intent.action = "android.settings.APP_NOTIFICATION_SETTINGS" + intent.putExtra("app_package", context.packageName) + intent.putExtra("app_uid", context.applicationInfo?.uid) + intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK } } @@ -132,6 +223,20 @@ class MyPageFragment : BindingFragment(R.layout.fragment_ override fun onStart() { super.onStart() mainViewModel.getUser() + initCheckNotificationPermission() + changeNotiButtonByPermission() + } + + private fun changeNotiButtonByPermission() { + if (isNotificationPermissionAllowed) { + binding.ivMypageAgree.isVisible = true + binding.llMypageAgreePermissionChange.isGone = true + binding.tvMypageAgreePermission.isGone = true + } else { + binding.ivMypageAgree.isGone = true + binding.llMypageAgreePermissionChange.isVisible = true + binding.tvMypageAgreePermission.isVisible = true + } } // 위니피드 프래그먼트에서 마이페이지로 전환 시, 바텀시트 바로 띄우도록 @@ -352,14 +457,23 @@ class MyPageFragment : BindingFragment(R.layout.fragment_ } private fun updateNotificationAllowSwitchState(data: User) { - when (data.fcmIsAllowed) { - true -> { - binding.ivMypageAgree.transitionToEnd() - } + if (isNotificationPermissionAllowed) { + binding.ivMypageAgree.isVisible = true + binding.llMypageAgreePermissionChange.isGone = true + binding.tvMypageAgreePermission.isGone = true + when (data.fcmIsAllowed) { + true -> { + binding.ivMypageAgree.transitionToState(R.id.end, 1) + } - false -> { - binding.ivMypageAgree.transitionToStart() + false -> { + binding.ivMypageAgree.transitionToState(R.id.start, 1) + } } + } else { + binding.ivMypageAgree.isGone = true + binding.llMypageAgreePermissionChange.isVisible = true + binding.tvMypageAgreePermission.isVisible = true } } @@ -412,6 +526,8 @@ class MyPageFragment : BindingFragment(R.layout.fragment_ private const val VAL_MY_PAGE_SCREEN = "MyPageFragment" private const val KEY_FROM_NOTI = "fromNoti" private const val KEY_FROM_WINEY_FEED = "fromWineyFeed" + private const val KEY_TO_MYFEED = "toMyFeed" + private const val TAG_NOTIFICATION_OFF_DIALOG = "offNotification" } } diff --git a/app/src/main/res/drawable/ic_mypage_change.xml b/app/src/main/res/drawable/ic_mypage_change.xml new file mode 100644 index 00000000..64a17e57 --- /dev/null +++ b/app/src/main/res/drawable/ic_mypage_change.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/fragment_my_page.xml b/app/src/main/res/layout/fragment_my_page.xml index 3edcd7f9..4d0f52fc 100644 --- a/app/src/main/res/layout/fragment_my_page.xml +++ b/app/src/main/res/layout/fragment_my_page.xml @@ -363,18 +363,57 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/v_mypage_line6"> - + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toBottomOf="parent"> + + + + + + + + + 취소 삭제하기 + + 알림을 끄시겠어요? + 앞으로 위니 제국에서 오는 편지를 받으실 수 없어요. + 취소 + 확인 + 절약을 인증할 수 있는\n사진을 업로드 해 주세요. 절약을 실천한\n모습을 보여주세요! @@ -89,6 +95,7 @@ 1:1 문의 이용약관 알림설정 + 기기 설정을 변경해야 알림을 받을 수 있어요 탈퇴하기 로그아웃 @@ -216,6 +223,7 @@ 죄송합니다. 다시 시도해주세요. 정상적으로 신고되었습니다 :) 죄송합니다. 신고접수에 실패하였습니다. + 기기 설정을 변경해야 알림을 받을 수 있어요 LV. 평민 ㆍ