NTP-65804 | add in app rating pop in coin redemption screen (#16628)
This commit is contained in:
committed by
GitHub
parent
df04393ded
commit
47c60844dd
@@ -137,6 +137,11 @@ fun CoinHistoryScreen(
|
||||
)
|
||||
}
|
||||
|
||||
// Track if userData came from bundle (for app rating popup logic)
|
||||
var isUserFromCoinRedemption by remember {
|
||||
mutableStateOf(bundle.getStringSafely(USER_DATA) != null)
|
||||
}
|
||||
|
||||
var isLeftToRightTransition by remember {
|
||||
val isLeftToRightTransition by bundle.bundleDelegate(defaultValue = true)
|
||||
mutableStateOf(isLeftToRightTransition)
|
||||
@@ -401,7 +406,14 @@ fun CoinHistoryScreen(
|
||||
}
|
||||
userData?.let { it ->
|
||||
if (!isReferralShareScreen) {
|
||||
RewardsShareScreen(navigator = navigator, userData = it) { userData = null }
|
||||
RewardsShareScreen(
|
||||
navigator = navigator,
|
||||
userData = it,
|
||||
isUserFromCoinRedemption = isUserFromCoinRedemption,
|
||||
) {
|
||||
userData = null
|
||||
isUserFromCoinRedemption = false
|
||||
}
|
||||
} else {
|
||||
ReferralShareScreen(
|
||||
navigator = navigator,
|
||||
|
||||
@@ -74,8 +74,12 @@ import com.navi.coin.utils.constant.ImageConstants.SHAREABILITY_LEFT_POLYGON_URL
|
||||
import com.navi.coin.utils.constant.ImageConstants.SHAREABILITY_RIGHT_POLYGON_URL
|
||||
import com.navi.coin.vm.RewardsShareScreenVm
|
||||
import com.navi.common.R
|
||||
import com.navi.common.firebaseremoteconfig.FirebaseRemoteConfigHelper
|
||||
import com.navi.common.firebaseremoteconfig.FirebaseRemoteConfigHelper.APP_RATING_POP_UP_DELAY_INTERVAL
|
||||
import com.navi.common.ui.compose.GratificationLottieAnimation
|
||||
import com.navi.common.uitron.model.action.CtaAction
|
||||
import com.navi.common.utils.PlayStoreInAppRatingHelper
|
||||
import com.navi.common.utils.log
|
||||
import com.navi.design.font.FontWeightEnum
|
||||
import com.navi.design.font.getFontWeight
|
||||
import com.navi.design.font.naviFontFamily
|
||||
@@ -83,6 +87,7 @@ import com.navi.design.theme.FF1F002A
|
||||
import com.navi.design.theme.WhiteFFFFFF
|
||||
import com.navi.naviwidgets.R as WidgetR
|
||||
import com.navi.rr.referral.models.ReferralContactList
|
||||
import com.navi.rr.utils.RewardsAppRatingHelper
|
||||
import com.navi.rr.utils.capturable
|
||||
import com.navi.rr.utils.ext.clickable
|
||||
import com.navi.rr.utils.ext.hideGenericShareLoader
|
||||
@@ -94,6 +99,7 @@ import com.navi.rr.utils.handleContactClick
|
||||
import com.navi.rr.utils.rememberCaptureController
|
||||
import com.navi.uitron.utils.transformations.moneyFormat
|
||||
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@OptIn(ExperimentalComposeApi::class)
|
||||
@@ -102,6 +108,7 @@ fun RewardsShareScreen(
|
||||
userData: ReferralContactList? = null,
|
||||
navigator: DestinationsNavigator,
|
||||
rewardsShareScreenVm: RewardsShareScreenVm = hiltViewModel(),
|
||||
isUserFromCoinRedemption: Boolean = false,
|
||||
onClose: () -> Unit,
|
||||
) {
|
||||
val context = LocalContext.current as CoinActivity
|
||||
@@ -113,6 +120,13 @@ fun RewardsShareScreen(
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
var absoluteTranslationY by remember { mutableFloatStateOf(2000f) }
|
||||
|
||||
var showAppRatingPopUp by remember { mutableStateOf(false) }
|
||||
|
||||
// show app rating pop up only when share screen is triggered post redemption
|
||||
val shouldShowAppRatingPopUp = remember {
|
||||
isUserFromCoinRedemption && RewardsAppRatingHelper.shouldShowAppRatingPopup()
|
||||
}
|
||||
|
||||
Init(
|
||||
screenName = Constants.SCREENS.REWARDS_SHARE_SCREEN_SCREEN_NAME,
|
||||
activity = context,
|
||||
@@ -120,6 +134,15 @@ fun RewardsShareScreen(
|
||||
navigator = navigator,
|
||||
)
|
||||
|
||||
val playStoreRatingHelper =
|
||||
remember(shouldShowAppRatingPopUp) {
|
||||
if (shouldShowAppRatingPopUp) {
|
||||
PlayStoreInAppRatingHelper(context, "rewards_share_screen")
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
BackHandler { absoluteTranslationY = 2000f }
|
||||
val translateYState by
|
||||
animateFloatAsState(
|
||||
@@ -144,6 +167,24 @@ fun RewardsShareScreen(
|
||||
|
||||
LaunchedEffect(Unit) { rewardsShareScreenVm.inflateData(userData) { message = it } }
|
||||
|
||||
// delay is to ensure playStoreRatingHelper initialisation completes
|
||||
LaunchedEffect(showAppRatingPopUp) {
|
||||
if (shouldShowAppRatingPopUp && showAppRatingPopUp) {
|
||||
delay(
|
||||
FirebaseRemoteConfigHelper.getLong(
|
||||
APP_RATING_POP_UP_DELAY_INTERVAL,
|
||||
defaultValue = 2000,
|
||||
)
|
||||
)
|
||||
RewardsAppRatingHelper.updateLastShownTime()
|
||||
try {
|
||||
playStoreRatingHelper?.inAppRating(context)
|
||||
} catch (e: Exception) {
|
||||
e.log()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
rewardsShareScreenVm.screenActions.collect { action ->
|
||||
when (action) {
|
||||
@@ -686,6 +727,7 @@ fun RewardsShareScreen(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
isRemoteLottie = false,
|
||||
showLottieInfiniteTimes = false,
|
||||
onAnimationStart = { showAppRatingPopUp = true },
|
||||
lottie = R.raw.gratifaction_confetti,
|
||||
)
|
||||
|
||||
|
||||
@@ -75,6 +75,7 @@ object Constants {
|
||||
const val METADATA_SUBTITLE = "metadata.subtitle"
|
||||
const val SCRATCH_CARD_EXPERIENCE = "SCRATCH_CARD_EXPERIENCE"
|
||||
const val DRIP_REWARD_VALUE = "dripRewardValue"
|
||||
const val APP_RATING_LAST_SHOWN_TIME = "APP_RATING_LAST_SHOWN_TIME"
|
||||
const val SCROLL_THRESHOLD_FOR_STATUS_BAR_COLOR_CHANGE =
|
||||
"SCROLL_THRESHOLD_FOR_STATUS_BAR_COLOR_CHANGE"
|
||||
const val SCROLL_THRESHOLD_FOR_STATUS_BAR_COLOR_CHANGE_IN_DP = 120
|
||||
|
||||
@@ -289,6 +289,9 @@ object FirebaseRemoteConfigHelper {
|
||||
const val OKHTTP_CUSTOM_DNS_EXPERIMENT_V2 = "OKHTTP_CUSTOM_DNS_EXPERIMENT_V2"
|
||||
const val OKHTTP_RETRY_EXPERIMENT = "OKHTTP_RETRY_EXPERIMENT"
|
||||
const val OKHTTP_CUSTOM_DNS_VALUE = "OKHTTP_CUSTOM_DNS_VALUE"
|
||||
const val APP_RATING_DAYS_INTERVAL = "APP_RATING_DAYS_INTERVAL"
|
||||
const val MIN_REWARD_AMOUNT_FOR_APP_RATING = "MIN_REWARD_AMOUNT_FOR_APP_RATING"
|
||||
const val APP_RATING_POP_UP_DELAY_INTERVAL = "APP_RATING_POP_UP_DELAY_INTERVAL"
|
||||
|
||||
// Events for firebase config
|
||||
private const val FIREBASE_REMOTE_CONFIG_FETCH_SUCCESS =
|
||||
|
||||
@@ -51,6 +51,8 @@ import com.navi.common.R
|
||||
import com.navi.common.uitron.model.action.ApiType
|
||||
import com.navi.common.uitron.model.action.CtaAction
|
||||
import com.navi.common.utils.Constants
|
||||
import com.navi.common.utils.PlayStoreInAppRatingHelper
|
||||
import com.navi.common.utils.log
|
||||
import com.navi.rr.common.constants.SCRATCH_CARD_GRATIFICATION_SCREEN
|
||||
import com.navi.rr.common.views.NaviRRLottieAnimationWithTimeout
|
||||
import com.navi.rr.common.widgetFactory.WidgetRenderer
|
||||
@@ -63,6 +65,7 @@ import com.navi.rr.scratchcard.utils.ScratchCardTheme.ThemeConfig.Companion.SCRA
|
||||
import com.navi.rr.scratchcard.utils.getLottieForScratchCard
|
||||
import com.navi.rr.scratchcard.utils.isFestiveTheme
|
||||
import com.navi.rr.scratchcard.vm.ScratchCardVM
|
||||
import com.navi.rr.utils.RewardsAppRatingHelper
|
||||
import com.navi.rr.utils.composeutils.Init
|
||||
import com.navi.rr.utils.constants.Constants.AUTO_REDEEM_KEY
|
||||
import com.navi.rr.utils.constants.Constants.BACK
|
||||
@@ -104,6 +107,23 @@ fun ScratchCardComposable(
|
||||
.orEmpty()
|
||||
.isNotEmpty()
|
||||
|
||||
var showAppRatingPopUp by remember { mutableStateOf(false) }
|
||||
|
||||
val rewardAmount = screenContent?.scratchCardResponse?.amount
|
||||
val shouldShowAppRatingPopup =
|
||||
remember(rewardAmount) {
|
||||
RewardsAppRatingHelper.shouldShowAppRatingPopupForReward(rewardAmount)
|
||||
}
|
||||
|
||||
val playStoreRatingHelper =
|
||||
remember(shouldShowAppRatingPopup) {
|
||||
if (shouldShowAppRatingPopup) {
|
||||
PlayStoreInAppRatingHelper(context, "scratch_card_composable")
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
screenContent?.scratchCardResponse?.rewardRefId?.let { scratchCardVM.setRequestId(it) }
|
||||
scratchCardVM.setScratchCardBackResponse(ScratchCardBackResponse.NotOpened)
|
||||
|
||||
@@ -171,6 +191,17 @@ fun ScratchCardComposable(
|
||||
)
|
||||
}
|
||||
|
||||
LaunchedEffect(showAppRatingPopUp) {
|
||||
if (shouldShowAppRatingPopup && showAppRatingPopUp) {
|
||||
RewardsAppRatingHelper.updateLastShownTime()
|
||||
try {
|
||||
playStoreRatingHelper?.inAppRating(context)
|
||||
} catch (e: Exception) {
|
||||
e.log()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BoxWithConstraints(
|
||||
modifier =
|
||||
Modifier.fillMaxSize()
|
||||
@@ -193,7 +224,10 @@ fun ScratchCardComposable(
|
||||
showLottieInfiniteTimes = false,
|
||||
lottieUrl = lottieUrl,
|
||||
lottie = getLottieForScratchCard(themeValue = theme),
|
||||
onAnimationEnd = { showConfetti = false },
|
||||
onAnimationEnd = {
|
||||
showConfetti = false
|
||||
showAppRatingPopUp = true
|
||||
},
|
||||
placeHolder = R.raw.gratifaction_confetti,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2024-2025 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navi.rr.utils
|
||||
|
||||
import com.navi.base.sharedpref.PreferenceManager
|
||||
import com.navi.base.utils.TrustedTimeAccessor
|
||||
import com.navi.common.firebaseremoteconfig.FirebaseRemoteConfigHelper
|
||||
import com.navi.common.firebaseremoteconfig.FirebaseRemoteConfigHelper.APP_RATING_DAYS_INTERVAL
|
||||
import com.navi.common.firebaseremoteconfig.FirebaseRemoteConfigHelper.MIN_REWARD_AMOUNT_FOR_APP_RATING
|
||||
|
||||
object RewardsAppRatingHelper {
|
||||
|
||||
private const val ONE_DAY_IN_MILLI_SECONDS = 24 * 60 * 60 * 1000L
|
||||
private const val APP_RATING_LAST_SHOWN_TIME = "APP_RATING_LAST_SHOWN_TIME"
|
||||
|
||||
/**
|
||||
* Determines whether the app rating popup should be shown based on:
|
||||
* 1. Time elapsed since last shown
|
||||
* 2. Firebase remote config threshold
|
||||
*
|
||||
* @return true if popup should be shown, false otherwise
|
||||
*/
|
||||
fun shouldShowAppRatingPopup(): Boolean {
|
||||
val lastUpdatedTime =
|
||||
PreferenceManager.getLongPreference(APP_RATING_LAST_SHOWN_TIME, defValue = 0L)
|
||||
val currentTimeInMillis = TrustedTimeAccessor.getCurrentTimeMillis()
|
||||
val daysThreshold =
|
||||
FirebaseRemoteConfigHelper.getLong(APP_RATING_DAYS_INTERVAL, defaultValue = 90)
|
||||
|
||||
if (daysThreshold < 0) {
|
||||
return false
|
||||
}
|
||||
|
||||
val timeDifferenceInMillis = currentTimeInMillis - lastUpdatedTime
|
||||
val daysSinceLastShown = timeDifferenceInMillis / ONE_DAY_IN_MILLI_SECONDS
|
||||
|
||||
return when {
|
||||
daysSinceLastShown >= daysThreshold -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the app rating popup should be shown for reward-based scenarios. Checks
|
||||
* both time-based conditions and reward amount threshold.
|
||||
*
|
||||
* @param rewardAmount The reward amount to validate against minimum threshold
|
||||
* @return true if popup should be shown, false otherwise
|
||||
*/
|
||||
fun shouldShowAppRatingPopupForReward(rewardAmount: Int?): Boolean {
|
||||
if (rewardAmount == null || rewardAmount <= 0) {
|
||||
return false
|
||||
}
|
||||
|
||||
val minRewardAmount =
|
||||
FirebaseRemoteConfigHelper.getLong(MIN_REWARD_AMOUNT_FOR_APP_RATING, defaultValue = 100)
|
||||
|
||||
return (rewardAmount >= minRewardAmount) && shouldShowAppRatingPopup()
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the last shown time to current time. Call this when the app rating popup is actually
|
||||
* displayed.
|
||||
*/
|
||||
fun updateLastShownTime() {
|
||||
val currentTimeInMillis = TrustedTimeAccessor.getCurrentTimeMillis()
|
||||
PreferenceManager.setLongPreference(APP_RATING_LAST_SHOWN_TIME, currentTimeInMillis)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user