From c510f230430ac79981ec4e9ab98b190b8dee2f51 Mon Sep 17 00:00:00 2001 From: Sohan Reddy Atukula Date: Thu, 12 Jun 2025 20:00:08 +0530 Subject: [PATCH] NTP-70420 | Sohan | Added Scratch card in Screen Overlay for Coin Drop (#16550) --- .../home/compose/activity/HomePageActivity.kt | 14 ++ .../home/ui/screen/HomeContentFrame.kt | 28 +++ .../handler/ScreenOverlayEffectHandler.kt | 16 ++ .../handler/ScreenOverlayHandler.kt | 4 + .../screenOverlay/model/ScreenOverlayData.kt | 2 + .../handler/ScratchCardEffectHandler.kt | 44 +++++ .../model/ScratchCardOverlayData.kt | 16 ++ .../model/ScratchCardOverlayEffect.kt | 18 ++ .../model/ScratchCardOverlayEvent.kt | 21 +++ .../model/ScratchCardOverlayState.kt | 29 +++ .../scratchcard/reducer/ScratchCardReducer.kt | 43 +++++ .../ui/ScratchCardOverlayRenderer.kt | 172 ++++++++++++++++++ .../utils/ScratchCardOverlayConstants.kt | 14 ++ .../viewModel/ScreenOverlayVM.kt | 16 +- .../viewModel/ScreenOverlayVMComponent.kt | 20 ++ .../ui/compose/ScratchCardRendererV2.kt | 4 + .../com/navi/rr/utils/constants/Constants.kt | 1 + 17 files changed, 461 insertions(+), 1 deletion(-) create mode 100644 android/app/src/main/java/com/naviapp/screenOverlay/scratchcard/handler/ScratchCardEffectHandler.kt create mode 100644 android/app/src/main/java/com/naviapp/screenOverlay/scratchcard/model/ScratchCardOverlayData.kt create mode 100644 android/app/src/main/java/com/naviapp/screenOverlay/scratchcard/model/ScratchCardOverlayEffect.kt create mode 100644 android/app/src/main/java/com/naviapp/screenOverlay/scratchcard/model/ScratchCardOverlayEvent.kt create mode 100644 android/app/src/main/java/com/naviapp/screenOverlay/scratchcard/model/ScratchCardOverlayState.kt create mode 100644 android/app/src/main/java/com/naviapp/screenOverlay/scratchcard/reducer/ScratchCardReducer.kt create mode 100644 android/app/src/main/java/com/naviapp/screenOverlay/scratchcard/ui/ScratchCardOverlayRenderer.kt create mode 100644 android/app/src/main/java/com/naviapp/screenOverlay/scratchcard/utils/ScratchCardOverlayConstants.kt diff --git a/android/app/src/main/java/com/naviapp/home/compose/activity/HomePageActivity.kt b/android/app/src/main/java/com/naviapp/home/compose/activity/HomePageActivity.kt index d139c7cc13..4ab514fa28 100644 --- a/android/app/src/main/java/com/naviapp/home/compose/activity/HomePageActivity.kt +++ b/android/app/src/main/java/com/naviapp/home/compose/activity/HomePageActivity.kt @@ -566,6 +566,20 @@ class HomePageActivity : ) } } + lifecycleScope.launch { + screenOverlayVM.scratchCardEffect.collect { + screenOverlayEffectHandler.handleScratchCardEffect( + effect = it, + deletedItemsMap = screenOverlayVM.deletedItemsMap, + triggerStateUpdateApiCall = { scratchCardTransitionState -> + screenOverlayVM.triggerStateUpdateApiCall( + scratchCardTransitionState, + naeScreenName = screenName, + ) + }, + ) + } + } } private fun observeScreenLockEnableStatus() { diff --git a/android/app/src/main/java/com/naviapp/home/compose/home/ui/screen/HomeContentFrame.kt b/android/app/src/main/java/com/naviapp/home/compose/home/ui/screen/HomeContentFrame.kt index f72f0568b6..0b248adb17 100644 --- a/android/app/src/main/java/com/naviapp/home/compose/home/ui/screen/HomeContentFrame.kt +++ b/android/app/src/main/java/com/naviapp/home/compose/home/ui/screen/HomeContentFrame.kt @@ -46,6 +46,9 @@ import com.naviapp.screenOverlay.bottomsheet.ui.HomeScreenBottomSheet import com.naviapp.screenOverlay.nudge.domain.model.event.NudgeEvent import com.naviapp.screenOverlay.nudge.initializer.InitScreenOverlayComponents import com.naviapp.screenOverlay.popup.ui.PopupRenderer +import com.naviapp.screenOverlay.scratchcard.model.ScratchCardOverlayEffect +import com.naviapp.screenOverlay.scratchcard.model.ScratchCardOverlayEvent +import com.naviapp.screenOverlay.scratchcard.ui.ScratchCardOverlayRenderer import com.naviapp.screenOverlay.viewModel.ScreenOverlayVM import com.naviapp.utils.navigateTo import com.naviapp.utils.navigateToGlobalSendMoney @@ -83,6 +86,7 @@ fun HomeContentFrame( ) val nudgeState by screenOverlayVM.nudgeState.collectAsStateWithLifecycle() val popupState by screenOverlayVM.popupState.collectAsStateWithLifecycle() + val scratchCardState by screenOverlayVM.scratchCardOverlayState.collectAsStateWithLifecycle() val qrScreenVisible by sharedVM.qrScreenVisibility.collectAsStateWithLifecycle() val drawerState = rememberNaviDrawerState(NaviDrawerValue.Closed) @@ -175,6 +179,30 @@ fun HomeContentFrame( ) { uiTronResponse -> HandleUitronRenderer(uiTronResponse, screenOverlayVM) } + + ScratchCardOverlayRenderer( + scratchCardOverlayState = scratchCardState, + popupState = popupState, + hpStates = hpStates, + homeVM = homeVM, + selectedTabId = selectedTabId, + onScratchComplete = { id -> + screenOverlayVM.sendEvent( + ScratchCardOverlayEvent.ScratchCardOverlayScratched(id) + ) + screenOverlayVM.setEffect { + ScratchCardOverlayEffect.OnScratchCardOverlayScratched(id) + } + }, + onDismiss = { id -> + if (scratchCardState.isScratched.not()) { + screenOverlayVM.setEffect { + ScratchCardOverlayEffect.OnScratchCardOverlayDismiss(id) + } + } + screenOverlayVM.sendEvent(ScratchCardOverlayEvent.DismissScratchCardOverlay(id)) + }, + ) }, contentScrim = { /*When the nudge container is expanded, a full-screen scrim will overlay the home page.*/ diff --git a/android/app/src/main/java/com/naviapp/screenOverlay/handler/ScreenOverlayEffectHandler.kt b/android/app/src/main/java/com/naviapp/screenOverlay/handler/ScreenOverlayEffectHandler.kt index 4516461bad..475cbc11f5 100644 --- a/android/app/src/main/java/com/naviapp/screenOverlay/handler/ScreenOverlayEffectHandler.kt +++ b/android/app/src/main/java/com/naviapp/screenOverlay/handler/ScreenOverlayEffectHandler.kt @@ -14,6 +14,8 @@ import com.naviapp.screenOverlay.model.OverlayItemStateUpdate import com.naviapp.screenOverlay.nudge.domain.model.effect.NudgeEffect import com.naviapp.screenOverlay.popup.model.PopupEffect import com.naviapp.screenOverlay.popup.model.PopupState +import com.naviapp.screenOverlay.scratchcard.handler.ScratchCardEffectHandler +import com.naviapp.screenOverlay.scratchcard.model.ScratchCardOverlayEffect import javax.inject.Inject import kotlinx.coroutines.flow.StateFlow @@ -23,6 +25,7 @@ constructor( private val nudgeEffectHandler: NudgeEffectHandler, private val popupEffectHandler: PopupEffectHandler, private val bottomSheetEffectHandler: BottomSheetEffectHandler, + private val scratchCardEffectHandler: ScratchCardEffectHandler, ) { fun handleNudgeEffect( effect: NudgeEffect, @@ -60,4 +63,17 @@ constructor( ) { bottomSheetEffectHandler.handleBottomSheetEffect(effect, handleUitronAction) } + + fun handleScratchCardEffect( + effect: ScratchCardOverlayEffect, + deletedItemsMap: MutableMap>, + triggerStateUpdateApiCall: + (scratchCardTransitionState: List) -> Unit, + ) { + scratchCardEffectHandler.handleScratchCardEffect( + effect, + deletedItemsMap, + triggerStateUpdateApiCall, + ) + } } diff --git a/android/app/src/main/java/com/naviapp/screenOverlay/handler/ScreenOverlayHandler.kt b/android/app/src/main/java/com/naviapp/screenOverlay/handler/ScreenOverlayHandler.kt index ac161204ce..1a6c65232e 100644 --- a/android/app/src/main/java/com/naviapp/screenOverlay/handler/ScreenOverlayHandler.kt +++ b/android/app/src/main/java/com/naviapp/screenOverlay/handler/ScreenOverlayHandler.kt @@ -18,6 +18,7 @@ import com.naviapp.screenOverlay.nudge.domain.model.data.NudgeListData import com.naviapp.screenOverlay.nudge.domain.model.data.StaticNudgeData import com.naviapp.screenOverlay.popup.model.PopupListData import com.naviapp.screenOverlay.repositories.ScreenOverlayRepository +import com.naviapp.screenOverlay.scratchcard.model.ScratchCardOverlayData import com.naviapp.screenOverlay.utils.NudgeConstants.NUDGE import com.naviapp.screenOverlay.utils.PopupConstants.COLLECT_REQUEST import com.naviapp.screenOverlay.utils.PopupConstants.POPUP @@ -41,6 +42,7 @@ constructor( popupListData: PopupListData?, bottomSheetData: BottomSheetData?, staticNudgeData: StaticNudgeData?, + scratchCardData: ScratchCardOverlayData?, ) -> Unit, onError: () -> Unit, naeScreenName: String, @@ -71,6 +73,7 @@ constructor( popupListData: PopupListData?, bottomSheetData: BottomSheetData?, staticNudgeData: StaticNudgeData?, + scratchCardData: ScratchCardOverlayData?, ) -> Unit, ) { response.data?.screenOverlayData?.let { screenOverlayData -> @@ -87,6 +90,7 @@ constructor( screenOverlayData.popupListData?.copy(popupList = updatedPopupList), screenOverlayData.bottomSheetData, screenOverlayData.staticNudgeData, + screenOverlayData.scratchCardData, ) collectRequestPopupExists = updatedPopupList?.any { it.popupType == COLLECT_REQUEST } ?: false diff --git a/android/app/src/main/java/com/naviapp/screenOverlay/model/ScreenOverlayData.kt b/android/app/src/main/java/com/naviapp/screenOverlay/model/ScreenOverlayData.kt index 59be384ad4..e18edc7ab3 100644 --- a/android/app/src/main/java/com/naviapp/screenOverlay/model/ScreenOverlayData.kt +++ b/android/app/src/main/java/com/naviapp/screenOverlay/model/ScreenOverlayData.kt @@ -12,6 +12,7 @@ import com.naviapp.screenOverlay.bottomsheet.model.BottomSheetData import com.naviapp.screenOverlay.nudge.domain.model.data.NudgeListData import com.naviapp.screenOverlay.nudge.domain.model.data.StaticNudgeData import com.naviapp.screenOverlay.popup.model.PopupListData +import com.naviapp.screenOverlay.scratchcard.model.ScratchCardOverlayData data class OverlayScreenStructure( @SerializedName("screenStructure") val screenOverlayData: ScreenOverlayData? = null @@ -22,4 +23,5 @@ data class ScreenOverlayData( @SerializedName("popupData") val popupListData: PopupListData? = null, @SerializedName("bottomSheetData") val bottomSheetData: BottomSheetData? = null, @SerializedName("staticNudgeData") val staticNudgeData: StaticNudgeData? = null, + @SerializedName("scratchCardData") val scratchCardData: ScratchCardOverlayData? = null, ) diff --git a/android/app/src/main/java/com/naviapp/screenOverlay/scratchcard/handler/ScratchCardEffectHandler.kt b/android/app/src/main/java/com/naviapp/screenOverlay/scratchcard/handler/ScratchCardEffectHandler.kt new file mode 100644 index 0000000000..cca2280874 --- /dev/null +++ b/android/app/src/main/java/com/naviapp/screenOverlay/scratchcard/handler/ScratchCardEffectHandler.kt @@ -0,0 +1,44 @@ +/* + * + * * Copyright © 2024-2025 by Navi Technologies Limited + * * All rights reserved. Strictly confidential + * + */ + +package com.naviapp.screenOverlay.scratchcard.handler + +import com.naviapp.screenOverlay.model.OverlayItemStateUpdate +import com.naviapp.screenOverlay.model.OverlayItemTransitionState +import com.naviapp.screenOverlay.scratchcard.model.ScratchCardOverlayEffect +import com.naviapp.screenOverlay.scratchcard.utils.ScratchCardOverlayConstants.SCRATCH_CARD +import javax.inject.Inject + +class ScratchCardEffectHandler @Inject constructor() { + fun handleScratchCardEffect( + effect: ScratchCardOverlayEffect, + deletedItemsMap: MutableMap>, + triggerStateUpdateApiCall: + (scratchCardTransitionState: List) -> Unit, + ) { + when (effect) { + is ScratchCardOverlayEffect.OnScratchCardOverlayDismiss -> { + if (deletedItemsMap[SCRATCH_CARD]?.contains(effect.id) != true) { + triggerStateUpdateApiCall( + mutableListOf( + OverlayItemStateUpdate(effect.id, OverlayItemTransitionState.PAUSED) + ) + ) + } + deletedItemsMap.getOrPut(SCRATCH_CARD) { mutableSetOf() }.add(effect.id) + } + + is ScratchCardOverlayEffect.OnScratchCardOverlayScratched -> { + triggerStateUpdateApiCall( + mutableListOf( + OverlayItemStateUpdate(effect.id, OverlayItemTransitionState.COMPLETED) + ) + ) + } + } + } +} diff --git a/android/app/src/main/java/com/naviapp/screenOverlay/scratchcard/model/ScratchCardOverlayData.kt b/android/app/src/main/java/com/naviapp/screenOverlay/scratchcard/model/ScratchCardOverlayData.kt new file mode 100644 index 0000000000..1d4da1c25a --- /dev/null +++ b/android/app/src/main/java/com/naviapp/screenOverlay/scratchcard/model/ScratchCardOverlayData.kt @@ -0,0 +1,16 @@ +/* + * + * * Copyright © 2025 by Navi Technologies Limited + * * All rights reserved. Strictly confidential + * + */ + +package com.naviapp.screenOverlay.scratchcard.model + +import com.navi.common.forge.model.ScreenDefinition + +data class ScratchCardOverlayData( + val screenDefinition: ScreenDefinition, + val amount: Int? = null, + val scratchCardId: String, +) diff --git a/android/app/src/main/java/com/naviapp/screenOverlay/scratchcard/model/ScratchCardOverlayEffect.kt b/android/app/src/main/java/com/naviapp/screenOverlay/scratchcard/model/ScratchCardOverlayEffect.kt new file mode 100644 index 0000000000..e43a82a2e3 --- /dev/null +++ b/android/app/src/main/java/com/naviapp/screenOverlay/scratchcard/model/ScratchCardOverlayEffect.kt @@ -0,0 +1,18 @@ +/* + * + * * Copyright © 2024-2025 by Navi Technologies Limited + * * All rights reserved. Strictly confidential + * + */ + +package com.naviapp.screenOverlay.scratchcard.model + +import androidx.compose.runtime.Immutable +import com.navi.common.basemvi.UiEffect + +@Immutable +sealed interface ScratchCardOverlayEffect : UiEffect { + data class OnScratchCardOverlayDismiss(val id: String) : ScratchCardOverlayEffect + + data class OnScratchCardOverlayScratched(val id: String) : ScratchCardOverlayEffect +} diff --git a/android/app/src/main/java/com/naviapp/screenOverlay/scratchcard/model/ScratchCardOverlayEvent.kt b/android/app/src/main/java/com/naviapp/screenOverlay/scratchcard/model/ScratchCardOverlayEvent.kt new file mode 100644 index 0000000000..132f2307e5 --- /dev/null +++ b/android/app/src/main/java/com/naviapp/screenOverlay/scratchcard/model/ScratchCardOverlayEvent.kt @@ -0,0 +1,21 @@ +/* + * + * * Copyright © 2025 by Navi Technologies Limited + * * All rights reserved. Strictly confidential + * + */ + +package com.naviapp.screenOverlay.scratchcard.model + +import androidx.compose.runtime.Immutable +import com.navi.common.basemvi.UiEvent + +@Immutable +sealed interface ScratchCardOverlayEvent : UiEvent { + data class UpdateScratchCardOverlayData(val data: ScratchCardOverlayData) : + ScratchCardOverlayEvent + + data class DismissScratchCardOverlay(val id: String) : ScratchCardOverlayEvent + + data class ScratchCardOverlayScratched(val id: String) : ScratchCardOverlayEvent +} diff --git a/android/app/src/main/java/com/naviapp/screenOverlay/scratchcard/model/ScratchCardOverlayState.kt b/android/app/src/main/java/com/naviapp/screenOverlay/scratchcard/model/ScratchCardOverlayState.kt new file mode 100644 index 0000000000..67bd610d0d --- /dev/null +++ b/android/app/src/main/java/com/naviapp/screenOverlay/scratchcard/model/ScratchCardOverlayState.kt @@ -0,0 +1,29 @@ +/* + * + * * Copyright © 2024-2025 by Navi Technologies Limited + * * All rights reserved. Strictly confidential + * + */ + +package com.naviapp.screenOverlay.scratchcard.model + +import androidx.compose.runtime.Immutable +import com.navi.common.basemvi.UiState + +@Immutable +data class ScratchCardOverlayState( + val isScratchCardVisible: Boolean, + val scratchCardData: ScratchCardOverlayData?, + val isScratched: Boolean, + val showCloseButton: Boolean, +) : UiState { + companion object { + val initialState = + ScratchCardOverlayState( + isScratchCardVisible = false, + scratchCardData = null, + isScratched = false, + showCloseButton = false, + ) + } +} diff --git a/android/app/src/main/java/com/naviapp/screenOverlay/scratchcard/reducer/ScratchCardReducer.kt b/android/app/src/main/java/com/naviapp/screenOverlay/scratchcard/reducer/ScratchCardReducer.kt new file mode 100644 index 0000000000..adcf3e0021 --- /dev/null +++ b/android/app/src/main/java/com/naviapp/screenOverlay/scratchcard/reducer/ScratchCardReducer.kt @@ -0,0 +1,43 @@ +/* + * + * * Copyright © 2024-2025 by Navi Technologies Limited + * * All rights reserved. Strictly confidential + * + */ + +package com.naviapp.screenOverlay.scratchcard.reducer + +import com.navi.common.basemvi.BaseReducer +import com.naviapp.screenOverlay.scratchcard.model.ScratchCardOverlayEvent +import com.naviapp.screenOverlay.scratchcard.model.ScratchCardOverlayState +import javax.inject.Inject + +class ScratchCardReducer @Inject constructor() : + BaseReducer { + override fun reduce( + previousState: ScratchCardOverlayState, + event: ScratchCardOverlayEvent, + ): ScratchCardOverlayState { + return when (event) { + is ScratchCardOverlayEvent.UpdateScratchCardOverlayData -> { + previousState.copy( + scratchCardData = event.data, + isScratchCardVisible = true, + isScratched = false, + showCloseButton = false, + ) + } + is ScratchCardOverlayEvent.DismissScratchCardOverlay -> { + previousState.copy( + isScratchCardVisible = false, + scratchCardData = null, + isScratched = false, + showCloseButton = false, + ) + } + is ScratchCardOverlayEvent.ScratchCardOverlayScratched -> { + previousState.copy(isScratched = true, showCloseButton = true) + } + } + } +} diff --git a/android/app/src/main/java/com/naviapp/screenOverlay/scratchcard/ui/ScratchCardOverlayRenderer.kt b/android/app/src/main/java/com/naviapp/screenOverlay/scratchcard/ui/ScratchCardOverlayRenderer.kt new file mode 100644 index 0000000000..9e4b4e78b7 --- /dev/null +++ b/android/app/src/main/java/com/naviapp/screenOverlay/scratchcard/ui/ScratchCardOverlayRenderer.kt @@ -0,0 +1,172 @@ +/* + * + * * Copyright © 2024-2025 by Navi Technologies Limited + * * All rights reserved. Strictly confidential + * + */ + +package com.naviapp.screenOverlay.scratchcard.ui + +import androidx.compose.animation.core.Spring +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.animation.core.spring +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableFloatStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.unit.dp +import com.navi.base.utils.orElse +import com.navi.base.utils.orZero +import com.navi.common.R +import com.navi.common.utils.EMPTY +import com.navi.rr.scratchcard.model.GratificationResponse +import com.navi.rr.scratchcard.model.ScratchCardResponse +import com.navi.rr.scratchcard.ui.compose.ScratchCardRendererV2 +import com.navi.rr.utils.constants.ScratchCardAnimationConstants.SCRATCH_CARD_DEFAULT_POSITION +import com.navi.rr.utils.constants.ScratchCardAnimationConstants.SCRATCH_CARD_INITIAL_POSITION +import com.navi.rr.utils.ext.clickable +import com.naviapp.home.compose.home.ui.content.isDelayedRenderingEnabled +import com.naviapp.home.model.BottomBarTabType +import com.naviapp.home.reducer.HpStates +import com.naviapp.home.viewmodel.HomeViewModel +import com.naviapp.screenOverlay.popup.model.PopupState +import com.naviapp.screenOverlay.scratchcard.model.ScratchCardOverlayState +import com.naviapp.screenOverlay.scratchcard.utils.ScratchCardOverlayConstants.SCRATCH_CARD_DEFAULT_AMOUNT +import com.naviapp.screenOverlay.scratchcard.utils.ScratchCardOverlayConstants.SCRATCH_CARD_DELAY_FOR_DELAYED_RENDERING +import kotlinx.coroutines.delay + +@Composable +fun ScratchCardOverlayRenderer( + scratchCardOverlayState: ScratchCardOverlayState, + popupState: PopupState, + selectedTabId: String, + hpStates: () -> HpStates, + homeVM: () -> HomeViewModel, + onScratchComplete: (String) -> Unit, + onDismiss: (String) -> Unit, +) { + var scratchCardDismissed by remember { mutableStateOf(false) } + var scratchCardAbsoluteTranslationState by remember { + mutableFloatStateOf(SCRATCH_CARD_INITIAL_POSITION) + } + val currentCardTranslateYState by + animateFloatAsState( + targetValue = scratchCardAbsoluteTranslationState, + animationSpec = + spring( + dampingRatio = Spring.DampingRatioLowBouncy, + stiffness = Spring.StiffnessLow, + ), + label = EMPTY, + ) + val delayedRenderingEnabled = isDelayedRenderingEnabled(homeVM) + var isReadyToRender by remember { mutableStateOf(!delayedRenderingEnabled) } + if ( + shouldShowScratchCard( + scratchCardOverlayState = scratchCardOverlayState, + popupState = popupState, + hpStates = hpStates, + selectedTabId = selectedTabId, + ) && scratchCardDismissed.not() + ) { + LaunchedEffect(delayedRenderingEnabled) { + if (delayedRenderingEnabled) { + delay(SCRATCH_CARD_DELAY_FOR_DELAYED_RENDERING) + isReadyToRender = true + } + } + if (isReadyToRender) { + LaunchedEffect(Unit) { + scratchCardAbsoluteTranslationState = SCRATCH_CARD_DEFAULT_POSITION + } + Box( + modifier = + Modifier.fillMaxSize() + .clickable(disableRipple = true) { + if (scratchCardOverlayState.isScratchCardVisible) { + onDismiss( + scratchCardOverlayState.scratchCardData?.scratchCardId.orEmpty() + ) + scratchCardDismissed = true + } + } + .background(Color.Black.copy(alpha = 0.9f)) + ) { + ScratchCardRendererV2( + modifier = Modifier.graphicsLayer { translationY = currentCardTranslateYState }, + screenContent = + GratificationResponse( + screenDefinition = + scratchCardOverlayState.scratchCardData?.screenDefinition, + scratchCardResponse = + ScratchCardResponse( + amount = + scratchCardOverlayState.scratchCardData + ?.amount + .orElse(SCRATCH_CARD_DEFAULT_AMOUNT) + ), + ), + shouldRender = true, + onBackPress = { + onDismiss(scratchCardOverlayState.scratchCardData?.scratchCardId.orEmpty()) + scratchCardDismissed = true + }, + onScratch = { + onScratchComplete( + scratchCardOverlayState.scratchCardData?.scratchCardId.orEmpty() + ) + }, + ) + if (scratchCardOverlayState.showCloseButton) { + Box( + modifier = + Modifier.padding( + start = 16.dp, + top = 40.dp, + bottom = 20.dp, + end = 16.dp, + ) + ) { + Image( + modifier = + Modifier.clickable(disableRipple = true) { + onDismiss( + scratchCardOverlayState.scratchCardData + ?.scratchCardId + .orEmpty() + ) + scratchCardDismissed = true + }, + painter = painterResource(R.drawable.ic_close_cross_white), + contentDescription = null, + ) + } + } + } + } + } +} + +private fun shouldShowScratchCard( + scratchCardOverlayState: ScratchCardOverlayState, + popupState: PopupState, + hpStates: () -> HpStates, + selectedTabId: String, +) = + selectedTabId == BottomBarTabType.HOME.name && + !(popupState.isPopupListVisible && popupState.popupList?.size.orZero() > 0) && + scratchCardOverlayState.isScratchCardVisible && + hpStates().isRenderingFirstTime.not() && + hpStates().profileDrawerState.not() diff --git a/android/app/src/main/java/com/naviapp/screenOverlay/scratchcard/utils/ScratchCardOverlayConstants.kt b/android/app/src/main/java/com/naviapp/screenOverlay/scratchcard/utils/ScratchCardOverlayConstants.kt new file mode 100644 index 0000000000..afbb0b8424 --- /dev/null +++ b/android/app/src/main/java/com/naviapp/screenOverlay/scratchcard/utils/ScratchCardOverlayConstants.kt @@ -0,0 +1,14 @@ +/* + * + * * Copyright © 2024-2025 by Navi Technologies Limited + * * All rights reserved. Strictly confidential + * + */ + +package com.naviapp.screenOverlay.scratchcard.utils + +object ScratchCardOverlayConstants { + const val SCRATCH_CARD = "scratch_card" + const val SCRATCH_CARD_DELAY_FOR_DELAYED_RENDERING: Long = 2000 + const val SCRATCH_CARD_DEFAULT_AMOUNT = 100 +} diff --git a/android/app/src/main/java/com/naviapp/screenOverlay/viewModel/ScreenOverlayVM.kt b/android/app/src/main/java/com/naviapp/screenOverlay/viewModel/ScreenOverlayVM.kt index 97f0e26ae4..b2f0bf7fbe 100644 --- a/android/app/src/main/java/com/naviapp/screenOverlay/viewModel/ScreenOverlayVM.kt +++ b/android/app/src/main/java/com/naviapp/screenOverlay/viewModel/ScreenOverlayVM.kt @@ -37,6 +37,10 @@ import com.naviapp.screenOverlay.popup.model.PopupEvent import com.naviapp.screenOverlay.popup.model.PopupListData import com.naviapp.screenOverlay.popup.model.PopupState import com.naviapp.screenOverlay.popup.reducer.PopupReducer +import com.naviapp.screenOverlay.scratchcard.model.ScratchCardOverlayData +import com.naviapp.screenOverlay.scratchcard.model.ScratchCardOverlayEvent +import com.naviapp.screenOverlay.scratchcard.model.ScratchCardOverlayState +import com.naviapp.screenOverlay.scratchcard.reducer.ScratchCardReducer import com.naviapp.screenOverlay.usecase.NudgeCacheUseCase import com.naviapp.utils.SelectiveRefreshHandler import dagger.hilt.android.lifecycle.HiltViewModel @@ -67,6 +71,8 @@ constructor( nudgeReducer = NudgeReducer(), popupReducer = PopupReducer(), bottomSheetReducer = BottomSheetReducer(), + initialScratchCardOverlayState = ScratchCardOverlayState.initialState, + scratchCardReducer = ScratchCardReducer(), ) { private val _redirectionCtaData = MutableSharedFlow() val redirectionCtaData = _redirectionCtaData.asSharedFlow() @@ -151,12 +157,18 @@ constructor( screenOverlayHandler.fetchNudgeData( deletedItemsMap = deletedItemsMap, lastClickedNudgeId = lastClickedNudgeId, - onSuccess = { nudgeData, popupData, bottomSheetData, staticNudgeData -> + onSuccess = { + nudgeData, + popupData, + bottomSheetData, + staticNudgeData, + scratchCardData -> handleScreenOverlayApiSuccess( nudgeData, popupData, bottomSheetData, staticNudgeData, + scratchCardData, ) }, onError = { handleScreenOverlayApiError() }, @@ -186,6 +198,7 @@ constructor( popupListData: PopupListData?, bottomSheetData: BottomSheetData?, staticNudgeData: StaticNudgeData?, + scratchCardData: ScratchCardOverlayData?, ) { sendEvent( NudgeEvent.UpdateNudgeList(nudgeCacheUseCase.getUpdatedNudgeList(nudgeListData?.nudges)) @@ -195,6 +208,7 @@ constructor( } bottomSheetData?.let { sendEvent(BottomSheetEvent.UpdateBottomSheetData(it)) } staticNudgeData?.let { sendEvent(NudgeEvent.UpdateStaticNudgeData(it)) } + scratchCardData?.let { sendEvent(ScratchCardOverlayEvent.UpdateScratchCardOverlayData(it)) } selectiveRefreshHandler.handleSuccessState( this, SelectiveRefreshHandler.NUDGE_SUCCESS_STATE, diff --git a/android/app/src/main/java/com/naviapp/screenOverlay/viewModel/ScreenOverlayVMComponent.kt b/android/app/src/main/java/com/naviapp/screenOverlay/viewModel/ScreenOverlayVMComponent.kt index 20b0f34388..60e4a01863 100644 --- a/android/app/src/main/java/com/naviapp/screenOverlay/viewModel/ScreenOverlayVMComponent.kt +++ b/android/app/src/main/java/com/naviapp/screenOverlay/viewModel/ScreenOverlayVMComponent.kt @@ -21,6 +21,9 @@ import com.naviapp.screenOverlay.nudge.domain.model.state.NudgeState import com.naviapp.screenOverlay.popup.model.PopupEffect import com.naviapp.screenOverlay.popup.model.PopupEvent import com.naviapp.screenOverlay.popup.model.PopupState +import com.naviapp.screenOverlay.scratchcard.model.ScratchCardOverlayEffect +import com.naviapp.screenOverlay.scratchcard.model.ScratchCardOverlayEvent +import com.naviapp.screenOverlay.scratchcard.model.ScratchCardOverlayState import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.MutableStateFlow @@ -34,9 +37,11 @@ abstract class ScreenOverlayVMComponent( initialNudgeState: NudgeState, initialPopupState: PopupState, initialBottomSheetState: BottomSheetState, + initialScratchCardOverlayState: ScratchCardOverlayState, private val nudgeReducer: BaseReducer, private val popupReducer: BaseReducer, private val bottomSheetReducer: BaseReducer, + private val scratchCardReducer: BaseReducer, ) : BaseVM() { private val _nudgeState: MutableStateFlow = MutableStateFlow(initialNudgeState) @@ -50,6 +55,15 @@ abstract class ScreenOverlayVMComponent( val popupState: StateFlow get() = _popupState.asStateFlow() + private val _scratchCardOverlayState: MutableStateFlow = + MutableStateFlow(initialScratchCardOverlayState) + val scratchCardOverlayState: StateFlow + get() = _scratchCardOverlayState.asStateFlow() + + private val _scratchCardOverlayEffects = + Channel(capacity = Channel.UNLIMITED) + val scratchCardEffect = _scratchCardOverlayEffects.receiveAsFlow() + private val _popupEffects = Channel(capacity = Channel.UNLIMITED) val popupEffect = _popupEffects.receiveAsFlow() @@ -75,6 +89,10 @@ abstract class ScreenOverlayVMComponent( val newState = bottomSheetReducer.reduce(_bottomSheetState.value, event) _bottomSheetState.update { newState } } + is ScratchCardOverlayEvent -> { + val newState = scratchCardReducer.reduce(_scratchCardOverlayState.value, event) + _scratchCardOverlayState.update { newState } + } } } @@ -84,6 +102,8 @@ abstract class ScreenOverlayVMComponent( is NudgeEffect -> _nudgeEffects.trySend(effect() as NudgeEffect) is PopupEffect -> _popupEffects.trySend(effect() as PopupEffect) is BottomSheetEffect -> _bottomSheetEffects.trySend(effect() as BottomSheetEffect) + is ScratchCardOverlayEffect -> + _scratchCardOverlayEffects.trySend(effect() as ScratchCardOverlayEffect) } } } diff --git a/android/navi-rr/src/main/java/com/navi/rr/scratchcard/ui/compose/ScratchCardRendererV2.kt b/android/navi-rr/src/main/java/com/navi/rr/scratchcard/ui/compose/ScratchCardRendererV2.kt index 20b4a80ce5..3eb1a81ddf 100644 --- a/android/navi-rr/src/main/java/com/navi/rr/scratchcard/ui/compose/ScratchCardRendererV2.kt +++ b/android/navi-rr/src/main/java/com/navi/rr/scratchcard/ui/compose/ScratchCardRendererV2.kt @@ -279,6 +279,10 @@ private fun CtaActionHandler( Constants.SCRATCH_MORE -> { scratchNext.invoke() } + Constants.SCRATCH_COMPLETE -> { + showConfetti.invoke() + onRewardDisbursement.invoke() + } Constants.COIN_TRANSFER_COMPLETE -> { onCoinLottieEnd?.invoke() } diff --git a/android/navi-rr/src/main/java/com/navi/rr/utils/constants/Constants.kt b/android/navi-rr/src/main/java/com/navi/rr/utils/constants/Constants.kt index 5412c3ccdd..c8fff15686 100644 --- a/android/navi-rr/src/main/java/com/navi/rr/utils/constants/Constants.kt +++ b/android/navi-rr/src/main/java/com/navi/rr/utils/constants/Constants.kt @@ -61,6 +61,7 @@ object Constants { const val NEXT_MILESTONE_POSITION = "NEXT_MILESTONE_POSITION" const val SCRATCH_STARTED = "scratchStarted" const val SCRATCH_MORE = "SCRATCH_MORE" + const val SCRATCH_COMPLETE = "SCRATCH_COMPLETE" const val COIN_TRANSFER_COMPLETE = "COIN_TRANSFER_COMPLETE" const val BALL_TRANSFER_COMPLETE = "BALL_TRANSFER_COMPLETE" const val BACK = "BACK"