diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 25dd527f..635c6e01 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -5,7 +5,6 @@
-
@@ -16,7 +15,6 @@
-
-
= IMAGE_PICK_MAX) {
return@setOnClickListener
}
- pickMultipleMedia.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
+ requestPermission()
}
}
@@ -387,19 +388,112 @@ class CertificateFragment : Fragment() {
//알림 권한 교육용 팝업
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
- fun showPermissionDialog() {
+ fun showNotificationPermissionDialog() {
MaterialAlertDialogBuilder(requireContext())
.setTitle(getString(R.string.certificate_scr_dialog_title))
.setMessage(getString(R.string.certificate_scr_dialog_message))
.setPositiveButton(getString(R.string.certificate_scr_dialog_positive_button)) { dialogInterface: DialogInterface, i: Int ->
- permissionResult.launch(
- Manifest.permission.POST_NOTIFICATIONS
- )
+ navigateToAppSetting()
}
.setNegativeButton(getString(R.string.certificate_scr_dialog_negative_button)) { dialogInterface: DialogInterface, i: Int ->
viewModel.insertCertificateInitInfo()
}.show()
}
+ private val multiplePermissionsLauncher = registerForActivityResult(
+ ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
+ permissions.entries.forEach { (permission, isGranted) ->
+ when(permission){
+ Manifest.permission.READ_EXTERNAL_STORAGE ->{
+ if (isGranted){
+ pickMultipleMedia.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
+ }else{
+ if (!shouldShowRequestPermissionRationale(Manifest.permission.READ_EXTERNAL_STORAGE)){
+ showPermissionSettiongDialog()
+ }else{
+ showStoragePermissionDialog()
+ }
+ }
+ }
+ Manifest.permission.READ_MEDIA_IMAGES -> {
+ if (isGranted){
+ pickMultipleMedia.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
+ }else{
+ if (!shouldShowRequestPermissionRationale(Manifest.permission.READ_MEDIA_IMAGES)){
+ showPermissionSettiongDialog()
+ }else{
+ showPermissionSettiongDialog()
+ }
+ }
+ }
+ }
+ }
+ }
+
+ fun showStoragePermissionDialog() {
+ MaterialAlertDialogBuilder(requireContext())
+ .setTitle(getString(R.string.permission_dialog_scr_guide))
+ .setMessage(getString(R.string.permission_dialog_scr_guide_message))
+ .setPositiveButton(getString(R.string.permission_dialog_scr_guide_select)) { dialogInterface: DialogInterface, i: Int ->
+ //권한 물어보기
+ requestPermission()
+ }
+ .setNegativeButton(getString(R.string.permission_dialog_scr_guide_cancel)) { dialogInterface: DialogInterface, i: Int ->
+ dialogInterface.cancel()
+ }.show()
+ }
+
+
+ //권한 설정 화면을 위한 다이얼로그 띄우는 메서드
+ fun showPermissionSettiongDialog() {
+ MaterialAlertDialogBuilder(requireContext())
+ .setMessage(getString(R.string.permission_dialog_scr_guide_setting))
+ .setPositiveButton(getString(R.string.permission_dialog_scr_guide_setting_select)) { dialogInterface: DialogInterface, i: Int ->
+ navigateToAppSetting()
+ }
+ .setNegativeButton(getString(R.string.permission_dialog_scr_guide_setting_cancel)) { dialogInterface: DialogInterface, i: Int ->
+ dialogInterface.cancel()
+ }.show()
+ }
+
+ //앱 권한 세팅 화면으로 이동키시는 메서드
+ fun navigateToAppSetting() {
+ val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
+ data = Uri.fromParts("package", requireContext().packageName, null)
+ }
+ startActivity(intent)
+ }
+ //권한 확인 및 요청 메서드
+ fun requestPermission(){
+ if (
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU &&
+ (ContextCompat.checkSelfPermission(requireContext(),
+ Manifest.permission.READ_MEDIA_IMAGES
+ ) == PermissionChecker.PERMISSION_GRANTED)
+ ) {
+ pickMultipleMedia.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
+ } else if (
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE
+ && ContextCompat.checkSelfPermission(requireContext(),
+ Manifest.permission.READ_MEDIA_IMAGES
+ ) == PermissionChecker.PERMISSION_DENIED
+ ) {
+ // 34이상이고 READ_MEDIA_VISUAL_USER_SELECTED만 허용되어있다면 권한 물어보는 다이얼로그를 띄워야함.
+ /*showPermissionDialog()*/
+ multiplePermissionsLauncher.launch(arrayOf(Manifest.permission.READ_MEDIA_IMAGES))
+ } else if (ContextCompat.checkSelfPermission(requireContext(),
+ Manifest.permission.READ_EXTERNAL_STORAGE
+ ) == PermissionChecker.PERMISSION_GRANTED
+ ) {
+ pickMultipleMedia.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
+ } else {
+ if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.S_V2){
+ //READ_EXTERNAL_STORAGE 권한 요청
+ multiplePermissionsLauncher.launch(arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE))
+ }else{
+ multiplePermissionsLauncher.launch(arrayOf(Manifest.permission.READ_MEDIA_IMAGES))
+ }
+ }
+ }
fun loadingTaskSettingStart() {
binding.run {
diff --git a/app/src/main/java/com/fitmate/fitmate/presentation/ui/onboarding/OnBoardingPermissionFragment.kt b/app/src/main/java/com/fitmate/fitmate/presentation/ui/onboarding/OnBoardingPermissionFragment.kt
index 8a647899..34228414 100644
--- a/app/src/main/java/com/fitmate/fitmate/presentation/ui/onboarding/OnBoardingPermissionFragment.kt
+++ b/app/src/main/java/com/fitmate/fitmate/presentation/ui/onboarding/OnBoardingPermissionFragment.kt
@@ -1,43 +1,61 @@
package com.fitmate.fitmate.presentation.ui.onboarding
+import android.Manifest
import android.content.Context
+import android.os.Build
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.annotation.RequiresApi
import androidx.fragment.app.Fragment
+import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
import com.fitmate.fitmate.R
import com.fitmate.fitmate.databinding.FragmentOnboardingPermissionBinding
+import com.fitmate.fitmate.presentation.viewmodel.OnBoardingViewModel
+import dagger.hilt.android.AndroidEntryPoint
+@AndroidEntryPoint
class OnBoardingPermissionFragment: Fragment() {
+ val permissions =
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU){
+ arrayOf(Manifest.permission.POST_NOTIFICATIONS,Manifest.permission.READ_MEDIA_IMAGES)
+ }else{
+ arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE)
+ }
+
private lateinit var binding: FragmentOnboardingPermissionBinding
+ private val viewModel: OnBoardingViewModel by viewModels()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentOnboardingPermissionBinding.inflate(layoutInflater)
+ binding.view = this
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
-
- binding.buttonFragmentOnboardingPermissionToLogin.setOnClickListener {
- //권한 물어보고 로그인 화면으로 이동
- //TODO 권한 리스트들 물어보기
- //TODO 온보딩 완료 값 로컬에 저장
- /*findNavController().navigate(R.id.action_onBoardingPermissionFragment_to_loginFragment)*/
+ viewModel.onboardingInquiryStatus.observe(viewLifecycleOwner){
+ if (it){
+ findNavController().navigate(R.id.action_onBoardingPermissionFragment_to_homeFragment)
+ }
}
}
+ fun setButtonClick() {
+ multiplePermissionsLauncher.launch(permissions)
+ }
- private fun onBoardingFinished() {
- val sharedPref = activity?.getSharedPreferences("onBoarding", Context.MODE_PRIVATE)
- val editor = sharedPref?.edit()
- editor?.putBoolean("Finished", true)
- editor?.apply()
+ val multiplePermissionsLauncher = registerForActivityResult(
+ ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
+ permissions.entries.forEach { (permission, isGranted) -> }
+ viewModel.saveOnBoardingStateInPref()
}
+
}
diff --git a/app/src/main/java/com/fitmate/fitmate/presentation/ui/onboarding/OnBoardingThirdFragment.kt b/app/src/main/java/com/fitmate/fitmate/presentation/ui/onboarding/OnBoardingThirdFragment.kt
index ec10606f..9cebcb35 100644
--- a/app/src/main/java/com/fitmate/fitmate/presentation/ui/onboarding/OnBoardingThirdFragment.kt
+++ b/app/src/main/java/com/fitmate/fitmate/presentation/ui/onboarding/OnBoardingThirdFragment.kt
@@ -12,10 +12,9 @@ import com.fitmate.fitmate.databinding.FragmentOnboardingThirdBinding
import com.fitmate.fitmate.presentation.viewmodel.OnBoardingViewModel
import dagger.hilt.android.AndroidEntryPoint
-@AndroidEntryPoint
-class OnBoardingThirdFragment: Fragment(R.layout.fragment_onboarding_third) {
+
+class OnBoardingThirdFragment: Fragment() {
private lateinit var binding: FragmentOnboardingThirdBinding
- private val viewModel: OnBoardingViewModel by viewModels()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@@ -27,22 +26,9 @@ class OnBoardingThirdFragment: Fragment(R.layout.fragment_onboarding_third) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
-
- observeSavePref()
- initViews()
- }
-
- private fun observeSavePref() {
- viewModel.onboardingInquiryStatus.observe(viewLifecycleOwner) {
- if (it) {
- findNavController().navigate(R.id.action_onboardingContainerFragment_to_homeFragment)
- }
- }
- }
-
- private fun initViews() {
binding.buttonFinishFragment.setOnClickListener {
- viewModel.saveOnBoardingStateInPref()
+ findNavController().navigate(R.id.action_onboardingContainerFragment_to_onBoardingPermissionFragment)
}
}
+
}
\ No newline at end of file
diff --git a/app/src/main/java/com/fitmate/fitmate/presentation/ui/userinfo/UserInfoFragment.kt b/app/src/main/java/com/fitmate/fitmate/presentation/ui/userinfo/UserInfoFragment.kt
index 7a244a9d..65ec781b 100644
--- a/app/src/main/java/com/fitmate/fitmate/presentation/ui/userinfo/UserInfoFragment.kt
+++ b/app/src/main/java/com/fitmate/fitmate/presentation/ui/userinfo/UserInfoFragment.kt
@@ -1,16 +1,24 @@
package com.fitmate.fitmate.presentation.ui.userinfo
+import android.Manifest.permission.READ_EXTERNAL_STORAGE
+import android.Manifest.permission.READ_MEDIA_IMAGES
import android.app.AlertDialog
+import android.content.DialogInterface
import android.content.Intent
import android.net.Uri
+import android.os.Build
import android.os.Bundle
import android.provider.MediaStore
+import android.provider.Settings
import android.util.Log
import android.view.View
import android.widget.ImageView
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
+import androidx.core.content.ContextCompat
+import androidx.core.content.PermissionChecker.PERMISSION_DENIED
+import androidx.core.content.PermissionChecker.PERMISSION_GRANTED
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import com.bumptech.glide.Glide
@@ -18,24 +26,56 @@ import com.bumptech.glide.request.RequestOptions
import com.fitmate.fitmate.R
import com.fitmate.fitmate.databinding.FragmentUserInfoBinding
import com.fitmate.fitmate.util.ControlActivityInterface
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.firebase.ktx.Firebase
import com.google.firebase.storage.ktx.storage
-class UserInfoFragment: Fragment(R.layout.fragment_user_info) {
+class UserInfoFragment : Fragment(R.layout.fragment_user_info) {
private lateinit var binding: FragmentUserInfoBinding
private lateinit var uri: Uri
- private val registerForActivityResult = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
- when (result.resultCode) {
- AppCompatActivity.RESULT_OK -> {
- uri = result.data?.data!!
- Log.d("testt",uri.toString())
- showImagePreview()
+ private val multiplePermissionsLauncher = registerForActivityResult(
+ ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
+ permissions.entries.forEach { (permission, isGranted) ->
+ when(permission){
+ READ_EXTERNAL_STORAGE ->{
+ if (isGranted){
+ accessGallery()
+ }else{
+ if (!shouldShowRequestPermissionRationale(READ_EXTERNAL_STORAGE)){
+ showPermissionSettiongDialog()
+ }else{
+ showPermissionDialog()
+ }
+ }
+ }
+ READ_MEDIA_IMAGES -> {
+ if (isGranted){
+ accessGallery()
+ }else{
+ if (!shouldShowRequestPermissionRationale(READ_MEDIA_IMAGES)){
+ showPermissionSettiongDialog()
+ }else{
+ showPermissionSettiongDialog()
+ }
+ }
+ }
}
}
}
+ private val registerForActivityResult =
+ registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
+ when (result.resultCode) {
+ AppCompatActivity.RESULT_OK -> {
+ uri = result.data?.data!!
+ Log.d("testt", uri.toString())
+ showImagePreview()
+ }
+ }
+ }
+
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentUserInfoBinding.bind(view)
@@ -47,9 +87,12 @@ class UserInfoFragment: Fragment(R.layout.fragment_user_info) {
private fun setClickListener() {
listOf(
- binding.textViewUserInfoContent1, binding.textViewUserInfoContent2,
- binding.textViewUserInfoContent3, binding.textViewUserInfoContent4,
- binding.textViewUserInfoContent5, binding.textViewUserInfoContent6
+ binding.textViewUserInfoContent1,
+ binding.textViewUserInfoContent2,
+ binding.textViewUserInfoContent3,
+ binding.textViewUserInfoContent4,
+ binding.textViewUserInfoContent5,
+ binding.textViewUserInfoContent6
).forEach { textView ->
textView.setOnClickListener { handleOnClick(textView.id) }
}
@@ -57,7 +100,7 @@ class UserInfoFragment: Fragment(R.layout.fragment_user_info) {
private fun handleOnClick(viewId: Int) {
when (viewId) {
- R.id.textViewUserInfoContent1 -> accessGallery()
+ R.id.textViewUserInfoContent1 -> requestPermission()//TODO 권한 체크로 변경하고 권한 체크하는 곳에서 이동하도록 변경
R.id.textViewUserInfoContent2 -> navigateFitOff()
R.id.textViewUserInfoContent3 -> announcement()
R.id.textViewUserInfoContent4 -> navigateLicense()
@@ -75,20 +118,15 @@ class UserInfoFragment: Fragment(R.layout.fragment_user_info) {
val preview = imagePreviewView.findViewById(R.id.imageViewPreview)
Glide.with(this).load(uri).into(preview)
- AlertDialog.Builder(requireContext())
- .setView(imagePreviewView)
+ AlertDialog.Builder(requireContext()).setView(imagePreviewView)
.setPositiveButton(android.R.string.ok) { dialog, _ ->
dialog.dismiss()
- Glide.with(this)
- .load(uri)
- .apply(RequestOptions().circleCrop())
+ Glide.with(this).load(uri).apply(RequestOptions().circleCrop())
.into(binding.imageViewUserInfoIcon)
imageUpload("test_user_id")
- }
- .setNegativeButton(android.R.string.cancel) { dialog, _ ->
+ }.setNegativeButton(android.R.string.cancel) { dialog, _ ->
dialog.dismiss()
- }
- .show()
+ }.show()
}
private fun imageUpload(userId: String) {
@@ -102,10 +140,11 @@ class UserInfoFragment: Fragment(R.layout.fragment_user_info) {
userRef.putFile(uri).addOnSuccessListener {
userRef.downloadUrl.addOnSuccessListener { downloadUri ->
val downloadURL = downloadUri.toString()
- activity.getSharedPreferences("UserInfo", AppCompatActivity.MODE_PRIVATE).edit().apply {
- putString("profileImageUri", uri.toString())
- apply()
- }
+ activity.getSharedPreferences("UserInfo", AppCompatActivity.MODE_PRIVATE).edit()
+ .apply {
+ putString("profileImageUri", uri.toString())
+ apply()
+ }
Toast.makeText(activity, "성공적으로 프로필 사진을 변경하였습니다.", Toast.LENGTH_SHORT).show()
}
@@ -115,18 +154,21 @@ class UserInfoFragment: Fragment(R.layout.fragment_user_info) {
}
private fun loadProfileImage() {
- val sharedPreferences = requireActivity().getSharedPreferences("UserInfo", AppCompatActivity.MODE_PRIVATE)
+ val sharedPreferences =
+ requireActivity().getSharedPreferences("UserInfo", AppCompatActivity.MODE_PRIVATE)
val profileImageUri = sharedPreferences.getString("profileImageUri", null)
profileImageUri?.let {
- Glide.with(this)
- .load(Uri.parse(it))
- .apply(RequestOptions().circleCrop())
+ Glide.with(this).load(Uri.parse(it)).apply(RequestOptions().circleCrop())
.into(binding.imageViewUserInfoIcon)
}
}
private fun accessGallery() {
- registerForActivityResult.launch(Intent(Intent.ACTION_PICK, MediaStore.Images.Media.INTERNAL_CONTENT_URI))
+ registerForActivityResult.launch(
+ Intent(
+ Intent.ACTION_PICK, MediaStore.Images.Media.INTERNAL_CONTENT_URI
+ )
+ )
}
private fun announcement() {
@@ -148,4 +190,63 @@ class UserInfoFragment: Fragment(R.layout.fragment_user_info) {
private fun navigateFitOff() {
navigateTo(R.id.action_userInfoFragment_to_myFitOffFragment)
}
+
+ //교육용 팝업 띄우는 메서드
+ fun showPermissionDialog() {
+ MaterialAlertDialogBuilder(requireContext())
+ .setTitle(getString(R.string.permission_dialog_scr_guide))
+ .setMessage(getString(R.string.permission_dialog_scr_guide_message))
+ .setPositiveButton(getString(R.string.permission_dialog_scr_guide_select)) { dialogInterface: DialogInterface, i: Int ->
+ //권한 물어보기
+ requestPermission()
+ }
+ .setNegativeButton(getString(R.string.permission_dialog_scr_guide_cancel)) { dialogInterface: DialogInterface, i: Int ->
+ dialogInterface.cancel()
+ }.show()
+ }
+
+ //권한 설정 화면을 위한 다이얼로그 띄우는 메서드
+ fun showPermissionSettiongDialog() {
+ MaterialAlertDialogBuilder(requireContext())
+ .setMessage(getString(R.string.permission_dialog_scr_guide_setting))
+ .setPositiveButton(getString(R.string.permission_dialog_scr_guide_setting_select)) { dialogInterface: DialogInterface, i: Int ->
+ navigateToAppSetting()
+ }
+ .setNegativeButton(getString(R.string.permission_dialog_scr_guide_setting_cancel)) { dialogInterface: DialogInterface, i: Int ->
+ dialogInterface.cancel()
+ }.show()
+ }
+
+ //앱 권한 세팅 화면으로 이동키시는 메서드
+ fun navigateToAppSetting() {
+ val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
+ data = Uri.fromParts("package", requireContext().packageName, null)
+ }
+ startActivity(intent)
+ }
+ //권한 확인 및 요청 메서드
+ fun requestPermission(){
+ if (
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU &&
+ (ContextCompat.checkSelfPermission(requireContext(), READ_MEDIA_IMAGES) == PERMISSION_GRANTED)
+ ) {
+ accessGallery()
+ } else if (
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE
+ && ContextCompat.checkSelfPermission(requireContext(), READ_MEDIA_IMAGES) == PERMISSION_DENIED
+ ) {
+ // 34이상이고 READ_MEDIA_VISUAL_USER_SELECTED만 허용되어있다면 권한 물어보는 다이얼로그를 띄워야함.
+ /*showPermissionDialog()*/
+ multiplePermissionsLauncher.launch(arrayOf(READ_MEDIA_IMAGES))
+ } else if (ContextCompat.checkSelfPermission(requireContext(), READ_EXTERNAL_STORAGE) == PERMISSION_GRANTED) {
+ accessGallery()
+ } else {
+ if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.S_V2){
+ //READ_EXTERNAL_STORAGE 권한 요청
+ multiplePermissionsLauncher.launch(arrayOf(READ_EXTERNAL_STORAGE))
+ }else{
+ multiplePermissionsLauncher.launch(arrayOf(READ_MEDIA_IMAGES))
+ }
+ }
+ }
}
diff --git a/app/src/main/res/layout/fragment_onboarding_permission.xml b/app/src/main/res/layout/fragment_onboarding_permission.xml
index ee5bf9e5..7f402b8d 100644
--- a/app/src/main/res/layout/fragment_onboarding_permission.xml
+++ b/app/src/main/res/layout/fragment_onboarding_permission.xml
@@ -3,7 +3,9 @@
xmlns:app="http://schemas.android.com/apk/res-auto">
-
+
diff --git a/app/src/main/res/navigation/nav_main_graph.xml b/app/src/main/res/navigation/nav_main_graph.xml
index 1fc14422..8e7a5fc9 100644
--- a/app/src/main/res/navigation/nav_main_graph.xml
+++ b/app/src/main/res/navigation/nav_main_graph.xml
@@ -31,10 +31,8 @@
android:name="com.fitmate.fitmate.presentation.ui.onboarding.OnboardingContainerFragment"
android:label="OnboardingContainerFragment" >
+ android:id="@+id/action_onboardingContainerFragment_to_onBoardingPermissionFragment"
+ app:destination="@id/onBoardingPermissionFragment" />
+ android:label="OnBoardingPermissionFragment" >
+
+
사진은 최대 5장까지 첨부할 수 있습니다!
종료 사진을 하나 이상 첨부해주세요!
인증 완료하기
- 정말 거부하시겠습니까?
+ 알림 권한이 없습니다!
알림 권한을 허용하지 않으면 인증 과정에서 운동 시간과 알림을 확인할 수 없습니다!
권한 허용하러가기
알림 없이 진행하기
@@ -161,5 +161,14 @@
그룹 투표 현황
+ 저장소 권한을 항상 모두 허용해야만 갤러리에 접근할 수 있습니다!
+ 권한 설정하러 가기
+ 취소
+
+ 정말 거부하시겠습니까?
+ 저장소 권한을 허용하지 않으면 사진 첨부를 할 수 없습니다!
+ 권한 허용하러가기
+ 취소
+
\ No newline at end of file