TP-64883 | Pinned widget feature (#10673)

Co-authored-by: Shaurya Rehan <shaurya.rehan@navi.com>
This commit is contained in:
Ujjwal Kumar
2024-05-17 00:39:31 +05:30
committed by GitHub
parent df869c5f12
commit 33d759ecaa
14 changed files with 343 additions and 83 deletions

View File

@@ -117,6 +117,11 @@ object FirebaseRemoteConfigHelper {
const val NAVI_PAY_ENABLE_VALIDATE_VPA_CACHING = "NAVI_PAY_ENABLE_VALIDATE_VPA_CACHING"
const val NAVI_PAY_VALIDATE_VPA_CACHING_TTL_IN_HOURS =
"NAVI_PAY_VALIDATE_VPA_CACHING_TTL_IN_HOURS"
const val NAVI_PAY_ENABLE_SCAN_PAY_PINNED_WIDGET = "NAVI_PAY_ENABLE_SCAN_PAY_PINNED_WIDGET"
const val NAVI_PAY_SCAN_AND_PAY_PINNED_WIDGET_REQUEST_MIN_DAYS =
"NAVI_PAY_SCAN_AND_PAY_PINNED_WIDGET_REQUEST_MIN_DAYS"
const val NAVI_PAY_SCAN_AND_PAY_PINNED_WIDGET_INITIAL_DELAY_IN_SECS =
"NAVI_PAY_SCAN_AND_PAY_PINNED_WIDGET_INITIAL_DELAY_IN_SECS"
// BBPS
const val NAVI_BBPS_CATEGORIES_CACHE_MILLIS = "NAVI_BBPS_CATEGORIES_CACHE_MILLIS"

View File

@@ -497,4 +497,12 @@
<key>NAVI_PAY_VALIDATE_VPA_CACHING_TTL_IN_HOURS</key>
<value>48</value>
</entry>
<entry>
<key>NAVI_PAY_SCAN_AND_PAY_PINNED_WIDGET_REQUEST_MIN_DAYS</key>
<value>7</value>
</entry>
<entry>
<key>NAVI_PAY_SCAN_AND_PAY_PINNED_WIDGET_INITIAL_DELAY_IN_SECS</key>
<value>5</value>
</entry>
</defaultsMap>

View File

@@ -2892,6 +2892,58 @@ class NaviPayAnalytics private constructor() {
}
}
inner class NaviPayWidgetManager {
fun onScanAndPayPinnedWidgetDisabled() {
NaviTrackEvent.trackEventOnClickStream(
"NaviPay_Dev_WidgetManager_ScanAndPayPinnedWidgetDisabled"
)
}
fun onScanAndPayPinnedWidgetTimeThresholdNotPassed(
lastRequestIntervalInDays: String,
minRequestIntervalInDays: String
) {
NaviTrackEvent.trackEventOnClickStream(
"NaviPay_Dev_WidgetManager_ScanAndPayPinnedWidgetTimeThresholdNotPassed",
mapOf(
"lastRequestIntervalInDays" to lastRequestIntervalInDays,
"minRequestIntervalInDays" to minRequestIntervalInDays
)
)
}
fun onScanAndPayPinnedWidgetBelowAndroid8() {
NaviTrackEvent.trackEventOnClickStream(
"NaviPay_Dev_WidgetManager_ScanAndPayPinnedWidgetBelowAndroid8"
)
}
fun onScanAndPayPinnedWidgetPinningNotSupported() {
NaviTrackEvent.trackEventOnClickStream(
"NaviPay_Dev_WidgetManager_ScanAndPayPinnedWidgetPinningNotSupported"
)
}
fun onScanAndPayPinnedWidgetAlreadyPinned() {
NaviTrackEvent.trackEventOnClickStream(
"NaviPay_Dev_WidgetManager_ScanAndPayPinnedWidgetAlreadyPinned"
)
}
fun onScanAndPayPinnedWidgetNotPinned() {
NaviTrackEvent.trackEventOnClickStream(
"NaviPay_Dev_WidgetManager_ScanAndPayPinnedWidgetNotPinned"
)
}
fun onScanAndPayPinnedWidgetRequested() {
NaviTrackEvent.trackEventOnClickStream(
"NaviPay_Dev_WidgetManager_ScanAndPayPinnedWidgetRequested"
)
}
}
companion object {
val INSTANCE = NaviPayAnalytics()
const val NAVI_HOME_SCREEN = "navi_home"

View File

@@ -28,6 +28,7 @@ import com.navi.pay.common.usecase.LinkedAccountsUseCase
import com.navi.pay.common.utils.DeviceInfoProvider
import com.navi.pay.common.utils.NaviPayCommonUtils
import com.navi.pay.common.utils.NaviPaySdkUtils
import com.navi.pay.common.widget.NaviPayWidgetManager
import com.navi.pay.db.NaviPayAppDatabase
import com.navi.pay.db.NaviPayAppEncryptedDatabase
import com.navi.pay.utils.KEY_UPI_LITE_ACTIVE_ACCOUNT_INFO
@@ -60,7 +61,8 @@ constructor(
private val naviPayAppEncryptedDatabase: Provider<NaviPayAppEncryptedDatabase>,
private val deviceInfoProvider: Provider<DeviceInfoProvider>,
private val linkedAccountsUseCase: Provider<LinkedAccountsUseCase>,
private val sharedPreferenceRepository: SharedPreferenceRepository
private val sharedPreferenceRepository: SharedPreferenceRepository,
private val naviPayWidgetManager: Provider<NaviPayWidgetManager>
) {
companion object {
lateinit var baseUrl: String
@@ -184,7 +186,7 @@ constructor(
logoutTasks.add(async { naviCacheRepository.get().clearOnLogout() })
logoutTasks.awaitAll()
}
NaviPayCommonUtils.removeScanAndPayShortcut(context = context)
naviPayWidgetManager.get().removeScanAndPayLauncherWidget()
}
fun isUserOnboarded(): Boolean {

View File

@@ -12,7 +12,6 @@ import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.VibrationEffect
import android.os.Vibrator
@@ -20,7 +19,6 @@ import android.provider.Settings
import android.telephony.SmsManager
import android.telephony.SubscriptionManager
import android.view.View
import androidx.annotation.DrawableRes
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
@@ -28,9 +26,6 @@ import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
import androidx.compose.ui.platform.SoftwareKeyboardController
import androidx.core.app.ActivityCompat
import androidx.core.content.pm.ShortcutInfoCompat
import androidx.core.content.pm.ShortcutManagerCompat
import androidx.core.graphics.drawable.IconCompat
import com.navi.analytics.utils.NaviTrackEvent
import com.navi.base.deeplink.util.DeeplinkConstants
import com.navi.base.model.CtaData
@@ -48,11 +43,9 @@ import com.navi.common.utils.log
import com.navi.pay.R
import com.navi.pay.common.model.view.NaviPayAccessEligibility
import com.navi.pay.common.model.view.NaviPayErrorConfig
import com.navi.pay.common.model.view.NaviPayScreenType
import com.navi.pay.common.model.view.SimInfo
import com.navi.pay.common.theme.color.NaviPayColor
import com.navi.pay.common.viewmodel.NaviPayBaseVM
import com.navi.pay.entry.NaviPayActivity
import com.navi.pay.management.common.sendmoney.model.network.TransactionInitiationType
import com.navi.pay.management.common.transaction.model.view.TransactionCategoryTags
import com.navi.pay.management.common.transaction.model.view.TransactionStatusOfView
@@ -72,14 +65,9 @@ import com.navi.pay.utils.DOT_IFSC_DOT_NPCI
import com.navi.pay.utils.INTENT_ACTION_SMS_DELIVERED
import com.navi.pay.utils.INTENT_ACTION_SMS_SENT
import com.navi.pay.utils.NAVI_PAY_FAIL_LOTTIE
import com.navi.pay.utils.NAVI_PAY_LOCAL_URI_SCHEME
import com.navi.pay.utils.NAVI_PAY_PAYMENT_STATUS_SUCCESS_LOTTIE
import com.navi.pay.utils.NAVI_PAY_PENDING_LOTTIE
import com.navi.pay.utils.NAVI_PAY_SCAN_AND_PAY_LAUNCHER_WIDGET_CLICKED
import com.navi.pay.utils.NAVI_PAY_SCAN_AND_PAY_SHORTCUT_ID
import com.navi.pay.utils.NAVI_PAY_SCAN_AND_PAY_WIDGET_ANALYTICS_EVENT_KEY
import com.navi.pay.utils.NAVI_PAY_TRANSACTION_HISTORY_TAG_SEPARATOR
import com.navi.pay.utils.NEEDS_RESULT
import com.navi.pay.utils.ONE_HOUR_IN_MILLIS
import com.navi.pay.utils.ONE_MINUTE_IN_MILLIS
import com.navi.pay.utils.PHONE_NUMBER_LENGTH
@@ -267,66 +255,6 @@ object NaviPayCommonUtils {
}
}
fun addScanAndPayShortcut(context: Context) {
if (
ShortcutManagerCompat.getDynamicShortcuts(context).any {
it.id == NAVI_PAY_SCAN_AND_PAY_SHORTCUT_ID
}
) {
return
}
val uri =
Uri.Builder()
.scheme(NAVI_PAY_LOCAL_URI_SCHEME)
.authority(NaviPayScreenType.NAVI_PAY_QR_SCANNER_SCREEN.name)
.build()
val scanAndPayShortcut =
getShortcutObject(
id = NAVI_PAY_SCAN_AND_PAY_SHORTCUT_ID,
shortLabel = context.getString(R.string.title_scan_and_pay),
longLabel = context.getString(R.string.title_scan_and_pay),
icon = R.drawable.ic_ps_scan_pay,
intent =
Intent(Intent.ACTION_VIEW, uri, context, NaviPayActivity::class.java).apply {
putExtra(NEEDS_RESULT, true)
putExtra(
NAVI_PAY_SCAN_AND_PAY_WIDGET_ANALYTICS_EVENT_KEY,
NAVI_PAY_SCAN_AND_PAY_LAUNCHER_WIDGET_CLICKED
)
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
},
context = context
)
ShortcutManagerCompat.pushDynamicShortcut(context, scanAndPayShortcut)
}
fun removeScanAndPayShortcut(context: Context) {
ShortcutManagerCompat.removeDynamicShortcuts(
context,
listOf(NAVI_PAY_SCAN_AND_PAY_SHORTCUT_ID)
)
}
private fun getShortcutObject(
id: String,
shortLabel: String,
longLabel: String,
@DrawableRes icon: Int,
intent: Intent,
context: Context
): ShortcutInfoCompat {
return ShortcutInfoCompat.Builder(context, id)
.setShortLabel(shortLabel)
.setLongLabel(longLabel)
.setIcon(IconCompat.createWithResource(context, icon))
.setIntent(intent)
.build()
}
fun getDateTimeObjectFromDateTimeString(
dateTime: String?,
timeZone: DateTimeZone = DateTimeZone.getDefault()

View File

@@ -17,6 +17,6 @@ import com.navi.pay.utils.NAVI_PAY_DATABASE_VALIDATE_VPA_CACHE_TABLE_NAME
data class ValidateVpaEntity(
@ColumnInfo(name = "vpa") @PrimaryKey val vpa: String,
@ColumnInfo(name = "response") val response: String,
@ColumnInfo(name = "updated_at") val updatedAt: Long = System.currentTimeMillis(),
@ColumnInfo(name = "updatedAt") val updatedAt: Long = System.currentTimeMillis(),
@ColumnInfo(name = "ttl") val ttl: Long
)

View File

@@ -0,0 +1,227 @@
/*
*
* * Copyright © 2024 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
package com.navi.pay.common.widget
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.ShortcutInfo
import android.content.pm.ShortcutManager
import android.net.Uri
import android.os.Build
import androidx.annotation.DrawableRes
import androidx.core.content.pm.ShortcutInfoCompat
import androidx.core.content.pm.ShortcutManagerCompat
import androidx.core.graphics.drawable.IconCompat
import com.navi.common.firebaseremoteconfig.FirebaseRemoteConfigHelper
import com.navi.common.firebaseremoteconfig.FirebaseRemoteConfigHelper.NAVI_PAY_ENABLE_SCAN_PAY_PINNED_WIDGET
import com.navi.common.firebaseremoteconfig.FirebaseRemoteConfigHelper.NAVI_PAY_SCAN_AND_PAY_PINNED_WIDGET_REQUEST_MIN_DAYS
import com.navi.pay.R
import com.navi.pay.analytics.NaviPayAnalytics
import com.navi.pay.common.model.view.NaviPayScreenType
import com.navi.pay.common.sync.model.view.SyncEntity
import com.navi.pay.common.sync.repository.SyncRepository
import com.navi.pay.entry.NaviPayActivity
import com.navi.pay.utils.NAVI_PAY_LOCAL_URI_SCHEME
import com.navi.pay.utils.NAVI_PAY_SCAN_AND_PAY_LAUNCHER_WIDGET_CLICKED
import com.navi.pay.utils.NAVI_PAY_SCAN_AND_PAY_LAUNCHER_WIDGET_SHORTCUT_ID
import com.navi.pay.utils.NAVI_PAY_SCAN_AND_PAY_WIDGET_ANALYTICS_EVENT_KEY
import com.navi.pay.utils.NAVI_PAY_SYNC_TABLE_SCAN_PAY_PINNED_WIDGET_KEY
import com.navi.pay.utils.NEEDS_RESULT
import dagger.hilt.android.qualifiers.ApplicationContext
import javax.inject.Inject
import kotlin.math.absoluteValue
import org.joda.time.DateTime
import org.joda.time.Days
/**
* LauncherWidget - When you long press on app icon & option is shown
*
* StaticWidget - When you long press on home screen & select widgets & then select app
*
* PinnedWidget - Adding launcher widget to home screen
*
* TileWidget - Widget appearing in notification panel
*/
interface NaviPayWidgetManager {
fun addScanAndPayLauncherWidget()
fun removeScanAndPayLauncherWidget()
suspend fun requestScanAndPayPinnedWidget()
}
class NaviPayWidgetManagerImpl
@Inject
constructor(
@ApplicationContext private val context: Context,
private val syncRepository: SyncRepository
) : NaviPayWidgetManager {
private val qrScannerUri by lazy {
Uri.Builder()
.scheme(NAVI_PAY_LOCAL_URI_SCHEME)
.authority(NaviPayScreenType.NAVI_PAY_QR_SCANNER_SCREEN.name)
.build()
}
private val qrScannerIntent by lazy {
Intent(Intent.ACTION_VIEW, qrScannerUri, context, NaviPayActivity::class.java).apply {
putExtra(NEEDS_RESULT, true)
putExtra(
NAVI_PAY_SCAN_AND_PAY_WIDGET_ANALYTICS_EVENT_KEY,
NAVI_PAY_SCAN_AND_PAY_LAUNCHER_WIDGET_CLICKED
)
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
}
}
private val naviPayAnalytics by lazy { NaviPayAnalytics.INSTANCE.NaviPayWidgetManager() }
private val shortcutManager by lazy {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
context.getSystemService(ShortcutManager::class.java)
} else {
null
}
}
override fun addScanAndPayLauncherWidget() {
if (
ShortcutManagerCompat.getDynamicShortcuts(context).any {
it.id == NAVI_PAY_SCAN_AND_PAY_LAUNCHER_WIDGET_SHORTCUT_ID
}
) { // Already added
return
}
val scanAndPayShortcut =
getShortcutObject(
id = NAVI_PAY_SCAN_AND_PAY_LAUNCHER_WIDGET_SHORTCUT_ID,
shortLabel = context.getString(R.string.title_scan_and_pay),
longLabel = context.getString(R.string.title_scan_and_pay),
icon = R.drawable.ic_ps_scan_pay,
intent = qrScannerIntent,
context = context
)
ShortcutManagerCompat.pushDynamicShortcut(context, scanAndPayShortcut)
}
override fun removeScanAndPayLauncherWidget() {
ShortcutManagerCompat.removeDynamicShortcuts(
context,
listOf(NAVI_PAY_SCAN_AND_PAY_LAUNCHER_WIDGET_SHORTCUT_ID)
)
}
override suspend fun requestScanAndPayPinnedWidget() {
if (!FirebaseRemoteConfigHelper.getBoolean(NAVI_PAY_ENABLE_SCAN_PAY_PINNED_WIDGET)) {
naviPayAnalytics.onScanAndPayPinnedWidgetDisabled()
return
}
val shortCutManager = shortcutManager ?: return
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
naviPayAnalytics.onScanAndPayPinnedWidgetBelowAndroid8()
return
}
if (!shortCutManager.isRequestPinShortcutSupported) {
naviPayAnalytics.onScanAndPayPinnedWidgetPinningNotSupported()
return
}
if (
shortCutManager.pinnedShortcuts.firstOrNull {
it.id == NAVI_PAY_SCAN_AND_PAY_LAUNCHER_WIDGET_SHORTCUT_ID && it.isPinned
} != null
) {
naviPayAnalytics.onScanAndPayPinnedWidgetAlreadyPinned()
return
} else {
naviPayAnalytics.onScanAndPayPinnedWidgetNotPinned()
}
val lastSyncedTimestamp =
syncRepository
.get(NAVI_PAY_SYNC_TABLE_SCAN_PAY_PINNED_WIDGET_KEY)
?.lastSyncedTimestamp
?.toLongOrNull() ?: 0L
val lastRequestIntervalInDays =
Days.daysBetween(DateTime(System.currentTimeMillis()), DateTime(lastSyncedTimestamp))
.days
.absoluteValue
val minRequestIntervalInDays =
FirebaseRemoteConfigHelper.getLong(NAVI_PAY_SCAN_AND_PAY_PINNED_WIDGET_REQUEST_MIN_DAYS)
if (lastRequestIntervalInDays < minRequestIntervalInDays) {
naviPayAnalytics.onScanAndPayPinnedWidgetTimeThresholdNotPassed(
lastRequestIntervalInDays = lastRequestIntervalInDays.toString(),
minRequestIntervalInDays = minRequestIntervalInDays.toString()
)
return
}
val scanAndPayShortcut =
ShortcutInfo.Builder(context, NAVI_PAY_SCAN_AND_PAY_LAUNCHER_WIDGET_SHORTCUT_ID).build()
val pinnedShortcutCallbackIntent =
shortCutManager.createShortcutResultIntent(scanAndPayShortcut)
val successCallback =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
PendingIntent.getBroadcast(
context,
0,
pinnedShortcutCallbackIntent,
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)
} else {
PendingIntent.getBroadcast(
context,
0,
pinnedShortcutCallbackIntent,
PendingIntent.FLAG_UPDATE_CURRENT
)
}
shortCutManager.requestPinShortcut(scanAndPayShortcut, successCallback.intentSender)
syncRepository.insert(
syncEntity =
SyncEntity(
key = NAVI_PAY_SYNC_TABLE_SCAN_PAY_PINNED_WIDGET_KEY,
lastSyncedTimestamp = System.currentTimeMillis().toString()
)
)
naviPayAnalytics.onScanAndPayPinnedWidgetRequested()
}
private fun getShortcutObject(
id: String,
shortLabel: String,
longLabel: String,
@DrawableRes icon: Int,
intent: Intent,
context: Context
): ShortcutInfoCompat {
return ShortcutInfoCompat.Builder(context, id)
.setShortLabel(shortLabel)
.setLongLabel(longLabel)
.setIcon(IconCompat.createWithResource(context, icon))
.setIntent(intent)
.build()
}
}

View File

@@ -135,7 +135,7 @@ class NaviPayActivity : BaseActivity() {
val isOnboarded = viewModel.isUserOnboarded()
if (isOnboarded) {
checkOnboardedUserMandatoryPermissions()
NaviPayCommonUtils.addScanAndPayShortcut(context = baseContext)
viewModel.addScanAndPayLauncherWidget()
} else {
onboardingResultLauncher.launch(
Intent(this, NaviPayOnboardingActivity::class.java).apply { data = intent?.data }

View File

@@ -35,6 +35,7 @@ import com.navi.pay.common.usecase.RefreshLinkedAccountsUseCase
import com.navi.pay.common.usecase.RefreshUiTronScreenResponseUseCase
import com.navi.pay.common.usecase.SyncLitmusExperimentsUseCase
import com.navi.pay.common.viewmodel.NaviPayBaseVM
import com.navi.pay.common.widget.NaviPayWidgetManager
import com.navi.pay.management.common.model.view.NudgeDetailEntity
import com.navi.pay.network.di.NaviPayGsonBuilder
import com.navi.pay.utils.FIRESTORE_BANK_UPTIME_COLLECTION_PATH
@@ -78,7 +79,8 @@ constructor(
private val scratchCardNudgeHelper: ScratchCardNudgeHelper,
private val naviCacheRepository: NaviCacheRepository,
private val syncLitmusExperimentsUseCase: SyncLitmusExperimentsUseCase,
@NaviPayGsonBuilder private val gson: Gson
@NaviPayGsonBuilder private val gson: Gson,
private val naviPayWidgetManager: NaviPayWidgetManager
) : NaviPayBaseVM(naviPayVmData = NaviPayVmData(screenName = NaviPayAnalytics.NAVI_PAY_ACTIVITY)) {
val BANK_UPTIME_POLLING_INTERVAL = 15.seconds
@@ -333,4 +335,6 @@ constructor(
}
}
}
fun addScanAndPayLauncherWidget() = naviPayWidgetManager.addScanAndPayLauncherWidget()
}

View File

@@ -15,6 +15,7 @@ import com.navi.base.utils.DateUtils
import com.navi.base.utils.orFalse
import com.navi.common.firebaseremoteconfig.FirebaseRemoteConfigHelper
import com.navi.common.firebaseremoteconfig.FirebaseRemoteConfigHelper.NAVI_PAY_REWARDS_GRATIFICATION_ENABLED
import com.navi.common.firebaseremoteconfig.FirebaseRemoteConfigHelper.NAVI_PAY_SCAN_AND_PAY_PINNED_WIDGET_INITIAL_DELAY_IN_SECS
import com.navi.common.network.models.RepoResult
import com.navi.common.network.models.isSuccess
import com.navi.common.network.models.isSuccessWithData
@@ -33,6 +34,7 @@ import com.navi.pay.common.utils.NaviPayCommonUtils.checkForDynamicQR
import com.navi.pay.common.utils.NaviPayCommonUtils.getPayeeVpaToDisplay
import com.navi.pay.common.utils.getTransactionDetailItemProperty
import com.navi.pay.common.viewmodel.NaviPayBaseVM
import com.navi.pay.common.widget.NaviPayWidgetManager
import com.navi.pay.destinations.SendMoneyScreenDestination
import com.navi.pay.management.common.model.view.NudgeDetailEntity
import com.navi.pay.management.common.paymentsummary.model.network.TransactionStatusRequest
@@ -68,6 +70,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
import kotlin.time.Duration.Companion.seconds
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
@@ -94,7 +97,8 @@ constructor(
private val liteAccountSyncUseCase: LiteAccountSyncUseCase,
private val scratchCardNudgeHelper: ScratchCardNudgeHelper,
private val naviPaySessionHelper: NaviPaySessionHelper,
private val rewardsNudgeEntityFetchUseCase: RewardsNudgeEntityFetchUseCase
private val rewardsNudgeEntityFetchUseCase: RewardsNudgeEntityFetchUseCase,
private val naviPayWidgetManager: NaviPayWidgetManager
) : NaviPayBaseVM(NaviPayVmData(screenName = NaviPayAnalytics.NAVI_PAY_PAYMENT_STATUS)) {
companion object {
@@ -269,6 +273,7 @@ constructor(
updateRewardsNudgeEntity()
pollForRewardsGratification()
startStatusPolling()
checkAndUpdateWidgets()
}
private suspend fun updateNavigateToNextScreenOnHelpCta(ctaData: CtaData?) {
@@ -737,6 +742,24 @@ constructor(
}
}
}
private fun checkAndUpdateWidgets() {
viewModelScope.launch(Dispatchers.IO) {
// Request for pinned widget only in case of successful transaction
// For 1st successful transaction, don't request pinned widget
if (
transactionStatus == TransactionStatus.SUCCESS && !isTransactionEligibleForNpsComms
) {
delay(
FirebaseRemoteConfigHelper.getDouble(
NAVI_PAY_SCAN_AND_PAY_PINNED_WIDGET_INITIAL_DELAY_IN_SECS
)
.seconds
)
naviPayWidgetManager.requestScanAndPayPinnedWidget()
}
}
}
}
sealed interface PaymentSummaryBottomSheetUIState {

View File

@@ -29,6 +29,8 @@ import com.navi.pay.common.utils.DeviceInfoImpl
import com.navi.pay.common.utils.DeviceInfoProvider
import com.navi.pay.common.utils.NaviPayCommonUtils
import com.navi.pay.common.utils.naviPayGsonBuilder
import com.navi.pay.common.widget.NaviPayWidgetManager
import com.navi.pay.common.widget.NaviPayWidgetManagerImpl
import com.navi.pay.db.NAVI_PAY_APP_DATABASE_MIGRATION_1_2
import com.navi.pay.db.NAVI_PAY_APP_DATABASE_MIGRATION_2_3
import com.navi.pay.db.NAVI_PAY_APP_DATABASE_MIGRATION_3_4
@@ -266,6 +268,12 @@ abstract class NaviPayDeviceModule {
@Singleton @Binds abstract fun bindImageCache(imageCacheImpl: ImageCacheImpl): ImageCache
@Singleton @Binds abstract fun bindSmsManager(smsManagerImpl: SmsManagerImpl): SmsManager
@Singleton
@Binds
abstract fun bindNaviPayWidgetManager(
naviPayWidgetManagerImpl: NaviPayWidgetManagerImpl
): NaviPayWidgetManager
}
@Qualifier @Retention(AnnotationRetention.BINARY) annotation class NaviPayRetrofit

View File

@@ -385,9 +385,7 @@ private fun ObserverSmsVerificationState(
SmsVerificationState.Success -> {
LaunchedEffect(Unit) {
naviPayAnalytics.simBindingSuccess()
NaviPayCommonUtils.addScanAndPayShortcut(
context = naviPayOnboardingActivity.baseContext
)
naviPayOnboardingViewModel.addScanAndPayLauncherWidget()
naviPayOnboardingViewModel.handleNavigationOnCustomerStatus()
}
}

View File

@@ -54,6 +54,7 @@ import com.navi.pay.common.usecase.SyncTransactionHistoryUseCase
import com.navi.pay.common.utils.DeviceInfoProvider
import com.navi.pay.common.utils.NaviPayCommonUtils
import com.navi.pay.common.viewmodel.NaviPayBaseVM
import com.navi.pay.common.widget.NaviPayWidgetManager
import com.navi.pay.onboarding.binding.model.network.BindDeviceRequest
import com.navi.pay.onboarding.binding.model.network.BindDeviceResponse
import com.navi.pay.onboarding.binding.model.network.BindDeviceStatusRequest
@@ -116,7 +117,8 @@ constructor(
private val syncFrequentTransactionsUseCase: SyncFrequentTransactionsUseCase,
private val syncSavedBeneficiariesUseCase: SyncSavedBeneficiariesUseCase,
private val resourceProvider: ResourceProvider,
savedStateHandle: SavedStateHandle
savedStateHandle: SavedStateHandle,
private val naviPayWidgetManager: NaviPayWidgetManager
) : NaviPayBaseVM(NaviPayVmData(screenName = NAVI_PAY_SETUP)) {
private val naviPayAnalytics: NaviPayAnalytics.NaviPaySetup =
@@ -941,6 +943,8 @@ constructor(
_onboardingAction.emit(NaviPayOnboardingAction.StartOnboarding)
}
fun addScanAndPayLauncherWidget() = naviPayWidgetManager.addScanAndPayLauncherWidget()
@OptIn(ExperimentalCoroutinesApi::class)
fun clearReplayCacheForHardUpdateParam() {
_isHardUpdateRequired.resetReplayCache()

View File

@@ -166,6 +166,7 @@ const val NAVI_PAY_SYNC_TABLE_SAVED_BENEFICIARY_KEY = "savedBeneficiaryKey"
const val NAVI_PAY_SYNC_TABLE_FREQUENT_TRANSACTIONS_KEY = "frequentTransactionsKey"
const val NAVI_PAY_LITMUS_EXPERIMENTS_LAST_REFRESHED_TIMESTAMP =
"litmusExperimentsLastRefreshedTimestamp"
const val NAVI_PAY_SYNC_TABLE_SCAN_PAY_PINNED_WIDGET_KEY = "scanPayPinnedWidgetKey"
// Generic
const val NAVIPAY_NETWORK_INFO_TIMEOUT = 65L
@@ -262,7 +263,7 @@ const val NAVI_PAY_DATABASE_BANK_UPTIME_TABLE = "bankUptime"
const val NAVI_PAY_DATABASE_VALIDATE_VPA_CACHE_TABLE_NAME = "validateVpaCache"
// Dynamic Shortcut
const val NAVI_PAY_SCAN_AND_PAY_SHORTCUT_ID = "scanAndPayShortcutId"
const val NAVI_PAY_SCAN_AND_PAY_LAUNCHER_WIDGET_SHORTCUT_ID = "scanAndPayShortcutId"
const val NAVI_PAY_SCAN_AND_PAY_WIDGET_ANALYTICS_EVENT_KEY =
"NaviPay_ScanAndPay_Widget_Clicked_Event_Key"
const val NAVI_PAY_SCAN_AND_PAY_LAUNCHER_WIDGET_CLICKED =