TP-73923 | Permission handling on qr and pay to contacts screen (#11795)
This commit is contained in:
@@ -17,11 +17,14 @@ import com.google.accompanist.permissions.rememberMultiplePermissionsState
|
||||
|
||||
sealed interface NaviPermissionResult {
|
||||
data object AllGranted : NaviPermissionResult
|
||||
// Here user has hard denied permission. App cannot ask permisison again..
|
||||
|
||||
// Here user has hard denied permission. App cannot ask permisison again..
|
||||
data object HardDenied : NaviPermissionResult
|
||||
|
||||
// Here user has denied permission so app can show a UI before asking for permission again.
|
||||
data object ShowRationale : NaviPermissionResult
|
||||
|
||||
data object None : NaviPermissionResult
|
||||
}
|
||||
|
||||
fun handlePermissionResult(
|
||||
|
||||
@@ -204,7 +204,8 @@ fun PaymentSummaryScreenV2(
|
||||
naviPayAnalytics = NaviPayAnalytics.INSTANCE.NaviPayPermission(),
|
||||
)
|
||||
}
|
||||
NaviPermissionResult.ShowRationale -> {}
|
||||
NaviPermissionResult.ShowRationale,
|
||||
NaviPermissionResult.None -> {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -285,6 +285,9 @@ fun QrScannerScreen(
|
||||
)
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
|
||||
package com.navi.pay.management.moneytransfer.scanpay.ui
|
||||
|
||||
import android.Manifest
|
||||
import android.content.pm.PackageManager
|
||||
import android.view.ScaleGestureDetector
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
@@ -77,6 +79,7 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.Lifecycle
|
||||
@@ -140,7 +143,6 @@ import com.navi.pay.utils.clearBackStackUpToAndNavigate
|
||||
import com.navi.pay.utils.clickableDebounce
|
||||
import com.navi.pay.utils.contactInitials
|
||||
import com.navi.pay.utils.launchPermissionSettingsScreen
|
||||
import com.navi.pay.utils.redirectToSettings
|
||||
import com.ramcosta.composedestinations.annotation.Destination
|
||||
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
@@ -165,6 +167,7 @@ fun QrScannerScreenV2(
|
||||
qrScannerViewModelV2.clickedContactPhoneNumber.collectAsStateWithLifecycle()
|
||||
val frequentTransactionsHeading by
|
||||
qrScannerViewModelV2.frequentTransactionsHeading.collectAsStateWithLifecycle()
|
||||
val permissionResult by qrScannerViewModelV2.permissionResult.collectAsStateWithLifecycle()
|
||||
|
||||
val onBackClick = { navigator.navigateUp(naviPayActivity) }
|
||||
|
||||
@@ -236,6 +239,26 @@ fun QrScannerScreenV2(
|
||||
qrScannerViewModelV2.navigateToNextScreen.collect { navigator.navigate(direction = it) }
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
val isPermissionGranted =
|
||||
ContextCompat.checkSelfPermission(
|
||||
naviPayActivity.baseContext,
|
||||
Manifest.permission.CAMERA
|
||||
) == PackageManager.PERMISSION_GRANTED
|
||||
|
||||
val shouldShowRationale =
|
||||
ActivityCompat.shouldShowRequestPermissionRationale(
|
||||
naviPayActivity,
|
||||
Manifest.permission.CAMERA
|
||||
)
|
||||
|
||||
// If permission is not granted and shouldShowRationale is false, the permission is hard
|
||||
// denied
|
||||
if (!isPermissionGranted && !shouldShowRationale) {
|
||||
qrScannerViewModelV2.updatePermissionResult(NaviPermissionResult.HardDenied)
|
||||
}
|
||||
}
|
||||
|
||||
val bottomSheetStateHolder by
|
||||
qrScannerViewModelV2.bottomSheetStateHolder.collectAsStateWithLifecycle()
|
||||
val turnOffCamera by qrScannerViewModelV2.shouldTurnOffCamera.collectAsStateWithLifecycle()
|
||||
@@ -285,7 +308,7 @@ fun QrScannerScreenV2(
|
||||
naviPaySessionAttributes =
|
||||
qrScannerViewModelV2.getNaviPaySessionAttributes()
|
||||
)
|
||||
// Camera screen will be shown on recomposition
|
||||
qrScannerViewModelV2.updatePermissionResult(it)
|
||||
}
|
||||
NaviPermissionResult.HardDenied -> {
|
||||
naviPayAnalytics.onCameraPermissionDenied(
|
||||
@@ -293,6 +316,7 @@ fun QrScannerScreenV2(
|
||||
naviPaySessionAttributes =
|
||||
qrScannerViewModelV2.getNaviPaySessionAttributes()
|
||||
)
|
||||
qrScannerViewModelV2.updatePermissionResult(it)
|
||||
}
|
||||
NaviPermissionResult.ShowRationale -> {
|
||||
naviPayAnalytics.onCameraPermissionDenied(
|
||||
@@ -300,12 +324,16 @@ fun QrScannerScreenV2(
|
||||
naviPaySessionAttributes =
|
||||
qrScannerViewModelV2.getNaviPaySessionAttributes()
|
||||
)
|
||||
qrScannerViewModelV2.updatePermissionResult(it)
|
||||
}
|
||||
else -> {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val onAllowPermissionButtonClick = {
|
||||
if (cameraPermissionsState.redirectToSettings()) {
|
||||
if (permissionResult is NaviPermissionResult.HardDenied) {
|
||||
naviPayActivity.launchPermissionSettingsScreen()
|
||||
naviPayAnalytics.onAppSettingsScreenLaunched(
|
||||
naviPaySessionAttributes = qrScannerViewModelV2.getNaviPaySessionAttributes()
|
||||
|
||||
@@ -29,6 +29,7 @@ import com.navi.pay.common.model.view.NaviPayErrorButtonConfig
|
||||
import com.navi.pay.common.model.view.NaviPayErrorConfig
|
||||
import com.navi.pay.common.model.view.NaviPaySessionHelper
|
||||
import com.navi.pay.common.model.view.NaviPayVmData
|
||||
import com.navi.pay.common.model.view.NaviPermissionResult
|
||||
import com.navi.pay.common.repository.CommonRepository
|
||||
import com.navi.pay.common.setup.NaviPayCustomerStatusHandler
|
||||
import com.navi.pay.common.setup.model.NaviPayCustomerStatus
|
||||
@@ -134,6 +135,10 @@ constructor(
|
||||
private val _clickedContactPhoneNumber = MutableStateFlow("")
|
||||
val clickedContactPhoneNumber = _clickedContactPhoneNumber.asStateFlow()
|
||||
|
||||
private val _permissionResult =
|
||||
MutableStateFlow<NaviPermissionResult>(NaviPermissionResult.None)
|
||||
val permissionResult = _permissionResult.asStateFlow()
|
||||
|
||||
private val frequentTransactionsTotalEntries =
|
||||
MutableStateFlow(naviPayDefaultConfig.config.frequentTransactionsTotalEntries)
|
||||
|
||||
@@ -589,6 +594,10 @@ constructor(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun updatePermissionResult(permissionResult: NaviPermissionResult) {
|
||||
_permissionResult.update { permissionResult }
|
||||
}
|
||||
}
|
||||
|
||||
enum class QrScannerBottomSheetUIStateV2 {
|
||||
|
||||
@@ -253,6 +253,9 @@ fun PayToContactsScreen(
|
||||
)
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
|
||||
package com.navi.pay.management.paytocontacts.ui
|
||||
|
||||
import android.Manifest
|
||||
import android.content.pm.PackageManager
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.Image
|
||||
@@ -54,6 +56,8 @@ import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||||
@@ -107,7 +111,6 @@ import com.navi.pay.utils.SELF_TRANSFER
|
||||
import com.navi.pay.utils.contactInitials
|
||||
import com.navi.pay.utils.customHide
|
||||
import com.navi.pay.utils.launchPermissionSettingsScreen
|
||||
import com.navi.pay.utils.redirectToSettings
|
||||
import com.ramcosta.composedestinations.annotation.Destination
|
||||
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
||||
import kotlinx.coroutines.android.awaitFrame
|
||||
@@ -152,6 +155,7 @@ fun PayToContactsScreenV2(
|
||||
payToContactsViewModelV2.showFrequentTransactionsSection.collectAsStateWithLifecycle()
|
||||
val shouldShowYourContactsTitle by
|
||||
payToContactsViewModelV2.shouldShowYourContactsTitle.collectAsStateWithLifecycle()
|
||||
val permissionResult by payToContactsViewModelV2.permissionResult.collectAsStateWithLifecycle()
|
||||
val isSelfTransferCtaVisible by
|
||||
payToContactsViewModelV2.isSelfTransferCtaVisible.collectAsStateWithLifecycle()
|
||||
|
||||
@@ -235,6 +239,26 @@ fun PayToContactsScreenV2(
|
||||
isDelayedOnboardingExperimentEnabled(bundle = naviPayActivity.intent.extras)
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
val isPermissionGranted =
|
||||
ContextCompat.checkSelfPermission(
|
||||
naviPayActivity.baseContext,
|
||||
Manifest.permission.READ_CONTACTS
|
||||
) == PackageManager.PERMISSION_GRANTED
|
||||
|
||||
val shouldShowRationale =
|
||||
ActivityCompat.shouldShowRequestPermissionRationale(
|
||||
naviPayActivity,
|
||||
Manifest.permission.READ_CONTACTS
|
||||
)
|
||||
|
||||
// If permission is not granted and shouldShowRationale is false, the permission is hard
|
||||
// denied
|
||||
if (!isPermissionGranted && !shouldShowRationale) {
|
||||
payToContactsViewModelV2.updatePermissionResult(NaviPermissionResult.HardDenied)
|
||||
}
|
||||
}
|
||||
|
||||
val readContactsPermissionsState =
|
||||
rememberMultiplePermissions(
|
||||
permissions =
|
||||
@@ -248,6 +272,7 @@ fun PayToContactsScreenV2(
|
||||
naviPaySessionAttributes =
|
||||
payToContactsViewModelV2.getNaviPaySessionAttributes()
|
||||
)
|
||||
payToContactsViewModelV2.updatePermissionResult(it)
|
||||
}
|
||||
NaviPermissionResult.HardDenied -> {
|
||||
naviPayAnalytics.onPayToContactsPermissionDenied(
|
||||
@@ -255,6 +280,7 @@ fun PayToContactsScreenV2(
|
||||
naviPaySessionAttributes =
|
||||
payToContactsViewModelV2.getNaviPaySessionAttributes()
|
||||
)
|
||||
payToContactsViewModelV2.updatePermissionResult(it)
|
||||
}
|
||||
NaviPermissionResult.ShowRationale -> {
|
||||
naviPayAnalytics.onPayToContactsPermissionDenied(
|
||||
@@ -262,12 +288,16 @@ fun PayToContactsScreenV2(
|
||||
naviPaySessionAttributes =
|
||||
payToContactsViewModelV2.getNaviPaySessionAttributes()
|
||||
)
|
||||
payToContactsViewModelV2.updatePermissionResult(it)
|
||||
}
|
||||
else -> {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val onAllowPermissionButtonClicked = {
|
||||
if (readContactsPermissionsState.redirectToSettings()) {
|
||||
if (permissionResult is NaviPermissionResult.HardDenied) {
|
||||
naviPayActivity.launchPermissionSettingsScreen()
|
||||
naviPayAnalytics.onAppSettingsScreenLaunched(
|
||||
naviPaySessionAttributes = payToContactsViewModelV2.getNaviPaySessionAttributes()
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.navi.pay.common.model.network.ValidateVpaRequest
|
||||
import com.navi.pay.common.model.network.ValidateVpaResponse
|
||||
import com.navi.pay.common.model.view.NaviPaySessionHelper
|
||||
import com.navi.pay.common.model.view.NaviPayVmData
|
||||
import com.navi.pay.common.model.view.NaviPermissionResult
|
||||
import com.navi.pay.common.repository.CommonRepository
|
||||
import com.navi.pay.common.usecase.LitmusExperimentsUseCase
|
||||
import com.navi.pay.common.usecase.NaviPayConfigUseCase
|
||||
@@ -140,6 +141,10 @@ constructor(
|
||||
private val _apiErrorMessage = MutableSharedFlow<String>()
|
||||
val apiErrorMessage = _apiErrorMessage.asSharedFlow()
|
||||
|
||||
private val _permissionResult =
|
||||
MutableStateFlow<NaviPermissionResult>(NaviPermissionResult.None)
|
||||
val permissionResult = _permissionResult.asStateFlow()
|
||||
|
||||
private val _isSavedContactListNonEmpty = MutableStateFlow(true)
|
||||
val isSavedContactListNonEmpty = _isSavedContactListNonEmpty.asStateFlow()
|
||||
|
||||
@@ -792,6 +797,10 @@ constructor(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun updatePermissionResult(permissionResult: NaviPermissionResult) {
|
||||
_permissionResult.update { permissionResult }
|
||||
}
|
||||
}
|
||||
|
||||
enum class PayToContactsUIStateV2 {
|
||||
|
||||
@@ -130,6 +130,9 @@ fun NaviPayOnboardingScreen(
|
||||
)
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -273,6 +273,9 @@ fun NaviPayOnboardingScreenV2(
|
||||
)
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,6 +352,9 @@ fun NaviPayOnboardingScreenV2(
|
||||
)
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,8 +54,6 @@ import androidx.paging.compose.LazyPagingItems
|
||||
import coil.request.ImageRequest
|
||||
import com.google.accompanist.navigation.material.BottomSheetNavigator
|
||||
import com.google.accompanist.navigation.material.ExperimentalMaterialNavigationApi
|
||||
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||||
import com.google.accompanist.permissions.MultiplePermissionsState
|
||||
import com.google.zxing.BarcodeFormat
|
||||
import com.google.zxing.EncodeHintType
|
||||
import com.google.zxing.qrcode.QRCodeWriter
|
||||
@@ -661,11 +659,6 @@ fun String.getIfscForBankUptime(): String {
|
||||
|
||||
fun getDefaultPayeeEntity() = PayeeEntity(name = "Default", vpa = "Default")
|
||||
|
||||
@OptIn(ExperimentalPermissionsApi::class)
|
||||
fun MultiplePermissionsState.redirectToSettings(): Boolean {
|
||||
return this.shouldShowRationale && !this.allPermissionsGranted
|
||||
}
|
||||
|
||||
fun Activity.launchPermissionSettingsScreen() {
|
||||
val intent =
|
||||
Intent(
|
||||
|
||||
Reference in New Issue
Block a user