NTP-59414 | Force update app for navi pay flow (#16055)
This commit is contained in:
committed by
GitHub
parent
048933dced
commit
b2dc18faf0
@@ -85,6 +85,8 @@ object FirebaseRemoteConfigHelper {
|
||||
// NAVI_PAY
|
||||
const val NAVI_PAY_MINIMUM_APP_VERSION_ALLOWED_FOR_ONBOARDING =
|
||||
"NAVI_PAY_MINIMUM_APP_VERSION_ALLOWED_FOR_ONBOARDING"
|
||||
const val NAVI_PAY_MINIMUM_APP_VERSION_ALLOWED_FOR_ACCESS =
|
||||
"NAVI_PAY_MINIMUM_APP_VERSION_ALLOWED_FOR_ACCESS"
|
||||
const val ENABLE_NAVI_PAY_KILL_SWITCH_MECHANISM = "ENABLE_NAVI_PAY_KILL_SWITCH_MECHANISM"
|
||||
const val NAVI_PAY_ENABLE_CRED_BLOCK_LOGS = "NAVI_PAY_ENABLE_CRED_BLOCK_LOGS"
|
||||
const val NAVI_PAY_ENABLE_VALIDATE_VPA_CACHING = "NAVI_PAY_ENABLE_VALIDATE_VPA_CACHING"
|
||||
|
||||
@@ -127,6 +127,7 @@ class NaviPayActivity : BaseActivity() {
|
||||
isErrorSheetCancellable = isCancelable
|
||||
},
|
||||
customerStatusRoute = customerStatusRoute,
|
||||
naviPayViewModel = viewModel,
|
||||
)
|
||||
} else {
|
||||
if (naviPayAccessEligibility.finish) {
|
||||
|
||||
@@ -14,24 +14,31 @@ import androidx.lifecycle.viewModelScope
|
||||
import com.google.firebase.firestore.DocumentSnapshot
|
||||
import com.google.firebase.firestore.QuerySnapshot
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.navi.base.cache.model.NaviCacheEntity
|
||||
import com.navi.base.cache.repository.NaviCacheRepository
|
||||
import com.navi.base.utils.BaseUtils.getPhoneNumberWithNinetyOneCode
|
||||
import com.navi.base.utils.FirestoreDataProvider
|
||||
import com.navi.common.firebaseremoteconfig.FirebaseRemoteConfigHelper
|
||||
import com.navi.common.model.AppUpgradeResponse
|
||||
import com.navi.common.payments.arc.usecase.ArcNudgeSyncUseCase
|
||||
import com.navi.common.upi.WITHOUT_ONBOARDING_FLOW
|
||||
import com.navi.common.usecase.SyncLitmusExperimentUseCase
|
||||
import com.navi.common.utils.EMPTY
|
||||
import com.navi.common.utils.NaviApiPoller
|
||||
import com.navi.pay.BuildConfig
|
||||
import com.navi.pay.analytics.NaviPayAnalytics
|
||||
import com.navi.pay.analytics.NaviPayAnalytics.Companion.NAVI_PAY_ACTIVITY
|
||||
import com.navi.pay.common.batman.DarkKnightScheduler
|
||||
import com.navi.pay.common.model.config.NaviPayDefaultConfig
|
||||
import com.navi.pay.common.model.view.NaviPayScreenType
|
||||
import com.navi.pay.common.model.view.PspType
|
||||
import com.navi.pay.common.setup.NaviPayCustomerStatusHandler
|
||||
import com.navi.pay.common.setup.NaviPayManager
|
||||
import com.navi.pay.common.setup.NaviPayRouter
|
||||
import com.navi.pay.common.usecase.BankUptimePollerUseCase
|
||||
import com.navi.pay.common.usecase.LiteAccountSyncUseCase
|
||||
import com.navi.pay.common.usecase.NaviPayConfigUseCase
|
||||
import com.navi.pay.common.usecase.RefreshBankListUseCase
|
||||
import com.navi.pay.common.usecase.RefreshConfigUseCase
|
||||
import com.navi.pay.common.usecase.RefreshLinkedAccountsUseCase
|
||||
@@ -45,6 +52,7 @@ import com.navi.pay.management.chat.util.SyncMessagesUseCase
|
||||
import com.navi.pay.management.upinumber.list.model.view.toUpiNumberEntity
|
||||
import com.navi.pay.management.upinumber.list.repository.UpiNumberRepository
|
||||
import com.navi.pay.network.di.NaviPayGsonBuilder
|
||||
import com.navi.pay.utils.DEFAULT_CONFIG
|
||||
import com.navi.pay.utils.FIRESTORE_CUSTOMER_DATA_COLLECTION_PATH
|
||||
import com.navi.pay.utils.FIRESTORE_PSP_ROUTING_BUCKETS_COLLECTION_PATH
|
||||
import com.navi.pay.utils.NAVI_PAY_LITMUS_EXPERIMENTS
|
||||
@@ -54,6 +62,15 @@ import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import javax.inject.Inject
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.asSharedFlow
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@HiltViewModel
|
||||
@@ -77,6 +94,7 @@ constructor(
|
||||
private val darkKnightScheduler: DarkKnightScheduler,
|
||||
private val syncConversationsUseCase: SyncConversationsUseCase,
|
||||
private val syncMessagesUseCase: SyncMessagesUseCase,
|
||||
private val naviPayConfigUseCase: NaviPayConfigUseCase,
|
||||
) : NaviPayBaseVM() {
|
||||
|
||||
private val naviPayAnalytics: NaviPayAnalytics.NaviPayViewModel =
|
||||
@@ -90,10 +108,51 @@ constructor(
|
||||
NaviApiPoller(repeatInterval = 5.seconds, numberOfIterations = 1)
|
||||
}
|
||||
|
||||
private val naviPayDefaultConfig =
|
||||
MutableStateFlow<NaviPayDefaultConfig>(NaviPayDefaultConfig())
|
||||
|
||||
val appUpgradeData =
|
||||
naviPayDefaultConfig
|
||||
.map { naviPayDefaultConfig ->
|
||||
AppUpgradeResponse(
|
||||
softUpgrade = true,
|
||||
hardUpgrade = false,
|
||||
expectedAppVersionCode = 0,
|
||||
downloadableUrl = EMPTY,
|
||||
verificationHash = EMPTY,
|
||||
updateType = EMPTY,
|
||||
title = naviPayDefaultConfig.config.appUpgradeTitle,
|
||||
description = naviPayDefaultConfig.config.appUpgradeDescription,
|
||||
)
|
||||
}
|
||||
.flowOn(Dispatchers.Default)
|
||||
.stateIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.WhileSubscribed(),
|
||||
initialValue =
|
||||
AppUpgradeResponse(
|
||||
softUpgrade = true,
|
||||
hardUpgrade = false,
|
||||
expectedAppVersionCode = 0,
|
||||
downloadableUrl = EMPTY,
|
||||
verificationHash = EMPTY,
|
||||
updateType = EMPTY,
|
||||
title = naviPayDefaultConfig.value.config.appUpgradeTitle,
|
||||
description = naviPayDefaultConfig.value.config.appUpgradeDescription,
|
||||
),
|
||||
)
|
||||
|
||||
private val _isHardUpdateRequired = MutableSharedFlow<Boolean>(replay = 1)
|
||||
val isHardUpdateRequired = _isHardUpdateRequired.asSharedFlow()
|
||||
|
||||
init {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
naviPayAnalytics.onNaviPayViewModelInit()
|
||||
|
||||
updateNaviPayDefaultConfig()
|
||||
|
||||
launch { performMinimumAllowedVersionForNaviPayAccessCheck() }
|
||||
|
||||
launch { refreshBankListUseCase.execute(screenName = screenName) }
|
||||
|
||||
launch { refreshConfigUseCase.execute(screenName = screenName) }
|
||||
@@ -139,6 +198,22 @@ constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun updateNaviPayDefaultConfig() {
|
||||
naviPayDefaultConfig.update {
|
||||
naviPayConfigUseCase.execute<NaviPayDefaultConfig>(
|
||||
configKey = DEFAULT_CONFIG,
|
||||
type = object : TypeToken<NaviPayDefaultConfig>() {}.type,
|
||||
screenName = screenName,
|
||||
) ?: NaviPayDefaultConfig()
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun performMinimumAllowedVersionForNaviPayAccessCheck() {
|
||||
if (isCurrentAppVersionLowerThanMinimumAllowedVersionForUpiUsage()) {
|
||||
_isHardUpdateRequired.emit(value = true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun initUpiLiteSync() {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
// Onboarding check is not required here
|
||||
@@ -146,6 +221,21 @@ constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun isCurrentAppVersionLowerThanMinimumAllowedVersionForUpiUsage(): Boolean {
|
||||
val currentAppVersion = NaviPayManager.appVersionCode.toIntOrNull() ?: Int.MAX_VALUE
|
||||
val minAppVersionAllowedForOnboarding =
|
||||
FirebaseRemoteConfigHelper.getLong(
|
||||
key = FirebaseRemoteConfigHelper.NAVI_PAY_MINIMUM_APP_VERSION_ALLOWED_FOR_ACCESS,
|
||||
defaultValue = 0L,
|
||||
)
|
||||
return currentAppVersion < minAppVersionAllowedForOnboarding
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
fun clearReplayCacheForHardUpdateParam() {
|
||||
_isHardUpdateRequired.resetReplayCache()
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used to get the route from the url This is needed when clicked from options in
|
||||
* SA home page, then get this route & override the default route of NavGraph to have faster
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
package com.navi.pay.entry.ui
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.compose.animation.AnimatedContentTransitionScope
|
||||
import androidx.compose.animation.EnterTransition
|
||||
import androidx.compose.animation.ExitTransition
|
||||
@@ -17,13 +18,18 @@ import androidx.compose.material.navigation.ModalBottomSheetLayout
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.rememberModalBottomSheetState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.navigation.NavBackStackEntry
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import androidx.navigation.plusAssign
|
||||
import com.navi.base.deeplink.DeepLinkManager
|
||||
import com.navi.base.deeplink.util.DeeplinkConstants
|
||||
import com.navi.base.model.CtaData
|
||||
import com.navi.base.utils.orFalse
|
||||
import com.navi.common.constants.APP_UPGRADE_DATA
|
||||
import com.navi.pay.NavGraphs
|
||||
import com.navi.pay.common.model.view.ErrorVisibilityEvent
|
||||
import com.navi.pay.common.model.view.NaviPayErrorButtonConfig
|
||||
@@ -32,6 +38,7 @@ import com.navi.pay.common.ui.NaviPayModalBottomSheet
|
||||
import com.navi.pay.common.ui.rememberBottomSheetNavigator
|
||||
import com.navi.pay.common.utils.ErrorEventHandler
|
||||
import com.navi.pay.entry.NaviPayActivity
|
||||
import com.navi.pay.entry.NaviPayViewModel
|
||||
import com.navi.pay.utils.ANIMATION_SPEC_DURATION_IN_MILLIS
|
||||
import com.navi.pay.utils.GenericErrorCtaHandler
|
||||
import com.ramcosta.composedestinations.DestinationsNavHost
|
||||
@@ -55,6 +62,7 @@ fun NaviPayMainScreen(
|
||||
genericErrorCtaHandler: GenericErrorCtaHandler,
|
||||
onErrorVisibilityChange: (Boolean, Boolean) -> Unit,
|
||||
customerStatusRoute: Route?,
|
||||
naviPayViewModel: NaviPayViewModel,
|
||||
) {
|
||||
val errorEvent by ErrorEventHandler.errorEvent.collectAsStateWithLifecycle(initialValue = null)
|
||||
val errorVisibilityEvent by
|
||||
@@ -69,6 +77,23 @@ fun NaviPayMainScreen(
|
||||
)
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
val appUpgradeData by naviPayViewModel.appUpgradeData.collectAsStateWithLifecycle()
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
naviPayViewModel.isHardUpdateRequired.collect {
|
||||
naviPayViewModel.clearReplayCacheForHardUpdateParam()
|
||||
if (it) {
|
||||
DeepLinkManager.getDeepLinkListener()
|
||||
?.navigateTo(
|
||||
activity = naviPayActivity,
|
||||
ctaData = CtaData(url = DeeplinkConstants.APP_UPDATE),
|
||||
bundle = Bundle().apply { putParcelable(APP_UPGRADE_DATA, appUpgradeData) },
|
||||
finish = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val dismissErrorSheet: () -> Unit = {
|
||||
onErrorVisibilityChange(false, confirmStateChange)
|
||||
scope
|
||||
|
||||
@@ -99,6 +99,7 @@ fun NaviPayOnboardingScreen(
|
||||
}
|
||||
val onboardingSource by
|
||||
naviPayOnboardingViewModel.onboardingSource.collectAsStateWithLifecycle()
|
||||
val appUpgradeData by naviPayOnboardingViewModel.appUpgradeData.collectAsStateWithLifecycle()
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
naviPayAnalytics.onNaviPaySetupLanded(
|
||||
@@ -119,13 +120,7 @@ fun NaviPayOnboardingScreen(
|
||||
?.navigateTo(
|
||||
activity = naviPayOnboardingActivity,
|
||||
ctaData = CtaData(url = DeeplinkConstants.APP_UPDATE),
|
||||
bundle =
|
||||
Bundle().apply {
|
||||
putParcelable(
|
||||
APP_UPGRADE_DATA,
|
||||
naviPayOnboardingViewModel.appUpgradeData,
|
||||
)
|
||||
},
|
||||
bundle = Bundle().apply { putParcelable(APP_UPGRADE_DATA, appUpgradeData) },
|
||||
finish = true,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -107,6 +107,7 @@ import com.navi.pay.permission.utils.PermissionKeys.NON_FIRST_TIME_SCREEN_PERMIS
|
||||
import com.navi.pay.permission.utils.PermissionUtils
|
||||
import com.navi.pay.tstore.list.usecase.SyncOrderHistoryUseCase
|
||||
import com.navi.pay.utils.ALLOW
|
||||
import com.navi.pay.utils.DEFAULT_CONFIG
|
||||
import com.navi.pay.utils.DENY
|
||||
import com.navi.pay.utils.INDIA_COUNTRY_CODE_WITHOUT_PLUS
|
||||
import com.navi.pay.utils.KEY_IS_FIRST_TRANSACTION_SUCCESSFUL
|
||||
@@ -144,10 +145,14 @@ import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.asSharedFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.serialization.json.Json
|
||||
@@ -294,19 +299,39 @@ constructor(
|
||||
totalPollingDurationInMillis = MAX_POLLING_DURATION_IN_MILLIS,
|
||||
)
|
||||
}
|
||||
private val naviPayDefaultConfig = NaviPayDefaultConfig()
|
||||
private val naviPayDefaultConfig =
|
||||
MutableStateFlow<NaviPayDefaultConfig>(NaviPayDefaultConfig())
|
||||
|
||||
val appUpgradeData =
|
||||
AppUpgradeResponse(
|
||||
softUpgrade = true,
|
||||
hardUpgrade = false,
|
||||
expectedAppVersionCode = 0,
|
||||
downloadableUrl = EMPTY,
|
||||
verificationHash = EMPTY,
|
||||
updateType = EMPTY,
|
||||
title = naviPayDefaultConfig.config.appUpgradeTitle,
|
||||
description = naviPayDefaultConfig.config.appUpgradeDescription,
|
||||
)
|
||||
naviPayDefaultConfig
|
||||
.map { naviPayDefaultConfig ->
|
||||
AppUpgradeResponse(
|
||||
softUpgrade = true,
|
||||
hardUpgrade = false,
|
||||
expectedAppVersionCode = 0,
|
||||
downloadableUrl = EMPTY,
|
||||
verificationHash = EMPTY,
|
||||
updateType = EMPTY,
|
||||
title = naviPayDefaultConfig.config.appUpgradeTitle,
|
||||
description = naviPayDefaultConfig.config.appUpgradeDescription,
|
||||
)
|
||||
}
|
||||
.flowOn(Dispatchers.Default)
|
||||
.stateIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.WhileSubscribed(),
|
||||
initialValue =
|
||||
AppUpgradeResponse(
|
||||
softUpgrade = true,
|
||||
hardUpgrade = false,
|
||||
expectedAppVersionCode = 0,
|
||||
downloadableUrl = EMPTY,
|
||||
verificationHash = EMPTY,
|
||||
updateType = EMPTY,
|
||||
title = naviPayDefaultConfig.value.config.appUpgradeTitle,
|
||||
description = naviPayDefaultConfig.value.config.appUpgradeDescription,
|
||||
),
|
||||
)
|
||||
|
||||
private companion object {
|
||||
private val POLLING_INTERVAL = 2.5.seconds
|
||||
@@ -327,11 +352,24 @@ constructor(
|
||||
private val locationPermissionRequestResult = Channel<Unit>()
|
||||
|
||||
init {
|
||||
updateNaviPayDefaultConfig()
|
||||
updateOnboardingIntentData()
|
||||
updateNaviPayOnboardingConfig()
|
||||
triggerNaviPaySetup()
|
||||
}
|
||||
|
||||
private fun updateNaviPayDefaultConfig() {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
naviPayDefaultConfig.update {
|
||||
naviPayConfigUseCase.execute<NaviPayDefaultConfig>(
|
||||
configKey = DEFAULT_CONFIG,
|
||||
type = object : TypeToken<NaviPayDefaultConfig>() {}.type,
|
||||
screenName = screenName,
|
||||
) ?: NaviPayDefaultConfig()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun triggerNaviPaySetup() {
|
||||
viewModelScope.safeLaunch(coroutineDispatcherProvider.io) {
|
||||
val phoneStatePermission =
|
||||
|
||||
Reference in New Issue
Block a user