TP-56773 reverse penny drop in PL journey (#10149)
Co-authored-by: soumya-ranjan_navi <soumya.ranjan@navi.com>
This commit is contained in:
@@ -19,6 +19,7 @@ import com.navi.ap.common.models.customwidget.DynamicGridWidgetData
|
||||
import com.navi.ap.common.models.customwidget.DynamicRadioGroupWithSectionsWidgetData
|
||||
import com.navi.ap.common.models.customwidget.DynamicRowWidgetData
|
||||
import com.navi.ap.common.models.customwidget.MappedRadioListWidgetData
|
||||
import com.navi.ap.common.models.customwidget.RadioGroupGridWidgetData
|
||||
import com.navi.ap.common.models.customwidget.StepTrackerWidgetData
|
||||
import com.navi.uitron.deserializer.UiTronDataDeserializer
|
||||
import com.navi.uitron.model.data.UiTronData
|
||||
@@ -57,6 +58,8 @@ class CustomUiTronDataDeserializer : UiTronDataDeserializer() {
|
||||
context?.deserialize(json, CameraWidgetData::class.java)
|
||||
CustomWidgets.CALENDAR_WIDGET.name ->
|
||||
context?.deserialize(json, CalendarWidgetData::class.java)
|
||||
CustomWidgets.RADIO_GROUP_GRID_WIDGET.name ->
|
||||
context?.deserialize(json, RadioGroupGridWidgetData::class.java)
|
||||
else -> super.deserialize(json, typeOfT, context)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
package com.navi.ap.common.handler
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import androidx.activity.compose.ManagedActivityResultLauncher
|
||||
@@ -24,6 +25,8 @@ import com.navi.ap.utils.getResolvedFieldValue
|
||||
import com.navi.common.uitron.model.action.LaunchDefaultIntentAction
|
||||
import com.navi.common.uitron.model.action.LaunchIntentAction
|
||||
import com.navi.common.uitron.model.action.LaunchIntentType
|
||||
import com.navi.common.uitron.model.action.LaunchTargetAppIntentAction
|
||||
import com.navi.common.utils.log
|
||||
|
||||
@Composable
|
||||
fun HandleLaunchIntentAction(viewModel: ApplicationPlatformVM) {
|
||||
@@ -37,7 +40,7 @@ fun HandleLaunchIntentAction(viewModel: ApplicationPlatformVM) {
|
||||
handleLaunchIntentAction(
|
||||
launchIntentAction = action,
|
||||
intentResult = intentResult,
|
||||
viewModel = viewModel,
|
||||
viewModel = viewModel
|
||||
)
|
||||
}
|
||||
else -> Unit
|
||||
@@ -68,6 +71,31 @@ private fun handleLaunchIntentAction(
|
||||
intentResult.launch(intent)
|
||||
}
|
||||
}
|
||||
LaunchIntentType.OPEN_TARGET_APP.name -> {
|
||||
(launchIntentAction.value as? LaunchTargetAppIntentAction)?.let { it ->
|
||||
var uri = it.intentUriString?.value
|
||||
it.intentUriString?.let {
|
||||
val resolvedValues =
|
||||
getResolvedFieldValue(fields = listOf(it), handle = viewModel.handle)
|
||||
uri = resolvedValues[it.sourceProperty]?.toString()
|
||||
}
|
||||
val intent =
|
||||
Intent().apply {
|
||||
action = it.intentAction
|
||||
data = Uri.parse(uri)
|
||||
}
|
||||
intent.setPackage(it.targetAppPackageName)
|
||||
try {
|
||||
intentResult.launch(intent)
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
viewModel.handleActions(it.onInitiateFailure)
|
||||
e.log()
|
||||
} catch (e: Exception) {
|
||||
viewModel.handleActions(it.onInitiateFailure)
|
||||
e.log()
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +71,18 @@ open class PLLambdaHandler(
|
||||
lambdaApiAction
|
||||
)
|
||||
}
|
||||
LambdaType.FETCH_FILTERED_UPI_APPS.name -> {
|
||||
lambdaImpl.fetchFilteredUPIApps(
|
||||
lambadaData.resolvedValue.toMutableMap(),
|
||||
lambdaApiAction,
|
||||
)
|
||||
}
|
||||
LambdaType.FETCH_RPD_PAYMENT_DETAILS.name -> {
|
||||
lambdaImpl.fetchRPDPaymentDetails(bridge.getSaveStateHandle(), lambdaApiAction)
|
||||
}
|
||||
LambdaType.POST_RPD_STATUS.name -> {
|
||||
lambdaImpl.postRPDStatus(lambdaApiAction)
|
||||
}
|
||||
LambdaType.VALIDATE_IFSC.name -> {
|
||||
lambdaImpl.validateIFSC(
|
||||
bridge.getSaveStateHandle(),
|
||||
|
||||
@@ -19,6 +19,7 @@ import com.navi.ap.common.models.lambdamodels.ConsentRequest
|
||||
import com.navi.ap.common.models.lambdamodels.RPDTokenRequestDetails
|
||||
import com.navi.ap.common.models.lambdamodels.request.EmiModel
|
||||
import com.navi.ap.common.models.lambdamodels.request.FetchPaymentMethodsRequest
|
||||
import com.navi.ap.common.models.lambdamodels.request.InstalledUpiApps
|
||||
import com.navi.ap.common.models.lambdamodels.request.KycMetadata
|
||||
import com.navi.ap.common.models.lambdamodels.request.KycSdkVerificationRequestData
|
||||
import com.navi.ap.common.models.lambdamodels.request.OfferDetails
|
||||
@@ -77,10 +78,12 @@ import com.navi.ap.utils.constants.OFFER_TYPE
|
||||
import com.navi.ap.utils.constants.PG_TOKEN
|
||||
import com.navi.ap.utils.constants.PIN_CODE
|
||||
import com.navi.ap.utils.constants.PREFERRED_BANKS_LIST
|
||||
import com.navi.ap.utils.constants.PREFERRED_UPI_APPS_LIST
|
||||
import com.navi.ap.utils.constants.RATE_OF_INTEREST
|
||||
import com.navi.ap.utils.constants.RPD_PAYMENT_METHOD_ID
|
||||
import com.navi.ap.utils.constants.RPD_PAYMENT_METHOD_TOKEN
|
||||
import com.navi.ap.utils.constants.RPD_PAYMENT_METHOD_UPI_LINK_KEY
|
||||
import com.navi.ap.utils.constants.RPD_PAYMENT_URI
|
||||
import com.navi.ap.utils.constants.S3_KEY
|
||||
import com.navi.ap.utils.constants.SEARCH_DEBOUNCE_TIME_IN_MILLIS
|
||||
import com.navi.ap.utils.constants.SELECTED_BANK
|
||||
@@ -111,6 +114,7 @@ import com.navi.common.uitron.model.action.LambdaApiAction
|
||||
import com.navi.common.uitron.model.action.SDKType
|
||||
import com.navi.common.utils.Constants.APP_PLATFORM_APPLICATION_ID
|
||||
import com.navi.common.utils.Constants.APP_PLATFORM_APPLICATION_TYPE
|
||||
import com.navi.common.utils.Constants.LIST_OF_INSTALLED_UPI_APPS
|
||||
import com.navi.common.utils.deviceId
|
||||
import com.navi.common.utils.toJsonObject
|
||||
import com.navi.naviwidgets.utils.FORWARD_SLASH
|
||||
@@ -599,6 +603,156 @@ internal class PLLambdaImpl(
|
||||
}
|
||||
}
|
||||
|
||||
fun fetchFilteredUPIApps(
|
||||
resolvedValues: MutableMap<String, Any?>,
|
||||
lambdaApiAction: LambdaApiAction,
|
||||
) {
|
||||
bridge.getViewModelScope().launch(Dispatchers.IO) {
|
||||
if (lambdaHandler.getClonedScreenDefinitionState() == null) {
|
||||
lambdaHandler.setClonedScreenDefinitionState(
|
||||
bridge.getScreenStructurePreRenderState()
|
||||
)
|
||||
}
|
||||
bridge.setLambdaState(LambdaState.Loading)
|
||||
val installedUpiApps = resolvedValues[LIST_OF_INSTALLED_UPI_APPS]
|
||||
val keyForPreferredUPIAppsListData =
|
||||
resolvedValues[PREFERRED_UPI_APPS_LIST]?.toString().orEmpty()
|
||||
val installedUpiAppsModel =
|
||||
InstalledUpiApps(
|
||||
listOfInstalledApps = installedUpiApps,
|
||||
apApplicationId = bridge.getQueryMap()[APP_PLATFORM_APPLICATION_ID]
|
||||
)
|
||||
bridge.executeActions(lambdaApiAction.preExecutionAction)
|
||||
val lambdaResponse = repository.fetchFilteredUPIApps(installedUpiAppsModel)
|
||||
bridge.setLambdaState(
|
||||
when {
|
||||
lambdaResponse.data.isNotNull() &&
|
||||
lambdaHandler.getClonedScreenDefinitionState().isNotNull() -> {
|
||||
bridge.getSaveStateHandle()[keyForPreferredUPIAppsListData] =
|
||||
lambdaResponse.data?.listOfEnabledApps
|
||||
val updatedResponse =
|
||||
PathInjector<ApScreenDefinitionStructure, Any?>()
|
||||
.injectData(
|
||||
lambdaHandler.getClonedScreenDefinitionState(),
|
||||
lambdaResponse.data
|
||||
)
|
||||
val updatedLambdaApiAction =
|
||||
PathInjector<LambdaApiAction, Any?>()
|
||||
.injectData(lambdaApiAction, lambdaResponse.data)
|
||||
|
||||
updatedResponse?.let {
|
||||
bridge.setScreenDefinitionState(
|
||||
ApScreenDefinitionState.PreRenderLoading(updatedResponse)
|
||||
)
|
||||
}
|
||||
bridge.executeActions(updatedLambdaApiAction.onSuccess)
|
||||
LambdaState.Success(LambdaResponseType())
|
||||
}
|
||||
lambdaResponse.errorBottomSheetStructure.isNotNull() -> {
|
||||
bridge.executeActions(lambdaApiAction.onFailure)
|
||||
LambdaState.Error(
|
||||
lambdaResponse.statusCode,
|
||||
lambdaResponse.errorBottomSheetStructure,
|
||||
lambdaResponse.genericErrorBottomSheetFields
|
||||
)
|
||||
}
|
||||
lambdaResponse.data.isNull() -> {
|
||||
getErrorBottomSheetStructureAndSetLambdaState(
|
||||
ApiType.GetScreenDefinition.name,
|
||||
lambdaResponse.statusCode
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
LambdaState.Nothing
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun fetchRPDPaymentDetails(
|
||||
handle: SavedStateHandle,
|
||||
lambdaApiAction: LambdaApiAction,
|
||||
) {
|
||||
bridge.getViewModelScope().launch(Dispatchers.IO) {
|
||||
bridge.setLambdaState(LambdaState.Loading)
|
||||
val token = handle.get<String>(RPD_PAYMENT_METHOD_TOKEN).orEmpty()
|
||||
bridge.executeActions(lambdaApiAction.preExecutionAction)
|
||||
val lambdaResponse = repository.fetchRPDPaymentDetails(token = token)
|
||||
bridge.setLambdaState(
|
||||
when {
|
||||
lambdaResponse.data.isNotNull() -> {
|
||||
val uri =
|
||||
lambdaResponse.data
|
||||
?.methodDetails
|
||||
?.providerConfigDetails
|
||||
?.upiLink
|
||||
.orEmpty()
|
||||
handle[RPD_PAYMENT_URI] = uri
|
||||
bridge.executeActions(lambdaApiAction.onSuccess)
|
||||
LambdaState.Success(LambdaResponseType())
|
||||
}
|
||||
lambdaResponse.errorBottomSheetStructure.isNotNull() -> {
|
||||
bridge.executeActions(lambdaApiAction.onFailure)
|
||||
LambdaState.Error(
|
||||
lambdaResponse.statusCode,
|
||||
lambdaResponse.errorBottomSheetStructure,
|
||||
lambdaResponse.genericErrorBottomSheetFields
|
||||
)
|
||||
}
|
||||
lambdaResponse.data.isNull() -> {
|
||||
getErrorBottomSheetStructureAndSetLambdaState(
|
||||
ApiType.GetScreenDefinition.name,
|
||||
lambdaResponse.statusCode
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
LambdaState.Nothing
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun postRPDStatus(
|
||||
lambdaApiAction: LambdaApiAction,
|
||||
) {
|
||||
bridge.getViewModelScope().launch(Dispatchers.IO) {
|
||||
bridge.setLambdaState(LambdaState.Loading)
|
||||
val handle = bridge.getSaveStateHandle()
|
||||
val token = handle.get<String>(RPD_PAYMENT_METHOD_TOKEN).orEmpty()
|
||||
val lambdaResponse = repository.postRPDStatus(token = token)
|
||||
bridge.setLambdaState(
|
||||
when {
|
||||
lambdaResponse.data.isNotNull() -> {
|
||||
val updatedLambdaApiAction =
|
||||
PathInjector<LambdaApiAction, Any?>()
|
||||
.injectData(lambdaApiAction, lambdaResponse.data)
|
||||
bridge.executeActions(updatedLambdaApiAction.onSuccess)
|
||||
LambdaState.Success(LambdaResponseType())
|
||||
}
|
||||
lambdaResponse.errorBottomSheetStructure.isNotNull() -> {
|
||||
bridge.executeActions(lambdaApiAction.onFailure)
|
||||
LambdaState.Error(
|
||||
lambdaResponse.statusCode,
|
||||
lambdaResponse.errorBottomSheetStructure,
|
||||
lambdaResponse.genericErrorBottomSheetFields
|
||||
)
|
||||
}
|
||||
lambdaResponse.data.isNull() -> {
|
||||
getErrorBottomSheetStructureAndSetLambdaState(
|
||||
ApiType.LambdaApiAction.name,
|
||||
lambdaResponse.statusCode
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
LambdaState.Nothing
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun validateIFSC(
|
||||
handle: SavedStateHandle,
|
||||
lambdaApiAction: LambdaApiAction,
|
||||
|
||||
@@ -15,11 +15,14 @@ import com.navi.ap.common.models.lambdamodels.RPDTokenData
|
||||
import com.navi.ap.common.models.lambdamodels.RPDTokenRequestDetails
|
||||
import com.navi.ap.common.models.lambdamodels.request.EmiModel
|
||||
import com.navi.ap.common.models.lambdamodels.request.FetchPaymentMethodsRequest
|
||||
import com.navi.ap.common.models.lambdamodels.request.InstalledUpiApps
|
||||
import com.navi.ap.common.models.lambdamodels.request.OfferDetails
|
||||
import com.navi.ap.common.models.lambdamodels.request.RPDPaymentData
|
||||
import com.navi.ap.common.models.lambdamodels.request.TelcoResendOtpRequest
|
||||
import com.navi.ap.common.models.lambdamodels.response.AgreementLetterDownloadResponse
|
||||
import com.navi.ap.common.models.lambdamodels.response.ApplyLoanResponse
|
||||
import com.navi.ap.common.models.lambdamodels.response.BankDataResponse
|
||||
import com.navi.ap.common.models.lambdamodels.response.FilteredUPIAppsResponse
|
||||
import com.navi.ap.common.models.lambdamodels.response.IfscBranchResponse
|
||||
import com.navi.ap.common.models.lambdamodels.response.KYCTrackerItemsListData
|
||||
import com.navi.ap.common.models.lambdamodels.response.KycSdkVerificationResponse
|
||||
@@ -157,6 +160,34 @@ class PLLambdaRepository @Inject constructor(private val retrofitService: APRetr
|
||||
return apiResponseCallback(response = response, apiTag = ApiType.LambdaApiAction.name)
|
||||
}
|
||||
|
||||
suspend fun fetchFilteredUPIApps(
|
||||
installedApps: InstalledUpiApps
|
||||
): ApRepoResult<FilteredUPIAppsResponse> {
|
||||
val response = retrofitService.sendUPIApps(data = installedApps, target = ORCHESTRATION_PL)
|
||||
logApiResponseEvents(methodName = ::fetchFilteredUPIApps.name, response = response)
|
||||
return apiResponseCallback(response = response, apiTag = ApiType.GetScreenDefinition.name)
|
||||
}
|
||||
|
||||
suspend fun fetchRPDPaymentDetails(token: String): ApRepoResult<RPDPaymentData> {
|
||||
val response =
|
||||
retrofitService.fetchRPDPaymentDetails(
|
||||
token = token,
|
||||
target = Constants.PAYMENT_GATEWAY_MODULE
|
||||
)
|
||||
logApiResponseEvents(methodName = ::fetchRPDPaymentDetails.name, response = response)
|
||||
return apiResponseCallback(response = response, apiTag = ApiType.GetScreenDefinition.name)
|
||||
}
|
||||
|
||||
suspend fun postRPDStatus(token: String): ApRepoResult<Any> {
|
||||
val response =
|
||||
retrofitService.postRPDStatus(
|
||||
token = token,
|
||||
target = Constants.PAYMENT_GATEWAY_MODULE,
|
||||
)
|
||||
logApiResponseEvents(methodName = ::postRPDStatus.name, response = response)
|
||||
return apiResponseCallback(response = response, apiTag = ApiType.LambdaApiAction.name)
|
||||
}
|
||||
|
||||
suspend fun validateIFSC(ifscCode: String): ApRepoResult<IfscBranchResponse> {
|
||||
val response = retrofitService.validateIFSC(ifscCode = ifscCode)
|
||||
logApiResponseEvents(methodName = ::validateIFSC.name, response = response)
|
||||
|
||||
@@ -55,4 +55,5 @@ enum class CustomWidgets {
|
||||
DYNAMIC_RADIO_GROUP_WITH_SECTIONS_WIDGET,
|
||||
CAMERA,
|
||||
CALENDAR_WIDGET,
|
||||
RADIO_GROUP_GRID_WIDGET
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2024 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navi.ap.common.models.customwidget
|
||||
|
||||
import com.navi.uitron.model.data.ImageData
|
||||
import com.navi.uitron.model.data.UiTronActionData
|
||||
import com.navi.uitron.model.data.UiTronData
|
||||
import com.navi.uitron.model.ui.ArrangementData
|
||||
import com.navi.uitron.model.ui.ComposePadding
|
||||
import com.navi.uitron.model.ui.ImageProperty
|
||||
import com.navi.uitron.model.ui.LazyGridProperty
|
||||
import com.navi.uitron.model.ui.TextProperty
|
||||
|
||||
data class RadioGroupGridWidgetData(
|
||||
val gridData: GridWidgetData? = null,
|
||||
val itemProperties: GridItem? = null,
|
||||
val itemData: GridItemData? = null,
|
||||
val selectedAction: UiTronActionData? = null,
|
||||
) : UiTronData()
|
||||
|
||||
data class GridItem(
|
||||
val mainImageProperty: ImageProperty? = null,
|
||||
val selectedImageProperty: ImageProperty? = null,
|
||||
val titleTextProperty: TextProperty? = null,
|
||||
val spaceBetweenImageAndText: Int? = 0,
|
||||
)
|
||||
|
||||
data class GridItemData(
|
||||
val selectedImageData: ImageData? = null,
|
||||
)
|
||||
|
||||
data class GridWidgetData(
|
||||
val minGridSize: Int? = 100,
|
||||
val maxGridSize: Int? = 1000,
|
||||
val gridCell: LazyGridProperty.GridCell? = null,
|
||||
val orientation: String? = LazyGridProperty.ORIENTATION_VERTICAL,
|
||||
val padding: ComposePadding? = null,
|
||||
val horizontalArrangementData: ArrangementData? = null,
|
||||
val verticalArrangementData: ArrangementData? = null,
|
||||
val defaultItemSelectedIndex: Int = -1
|
||||
)
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2024 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navi.ap.common.models.lambdamodels.request
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class InstalledUpiApps(
|
||||
@SerializedName("listOfInstalledApps") val listOfInstalledApps: Any? = null,
|
||||
@SerializedName("apApplicationId") val apApplicationId: String? = null
|
||||
)
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2024 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navi.ap.common.models.lambdamodels.request
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class RPDPaymentData(
|
||||
@SerializedName("responseType") val responseType: String? = null,
|
||||
@SerializedName("actionType") val actionType: String? = null,
|
||||
@SerializedName("methodDetails") val methodDetails: MethodDetails? = null
|
||||
) {
|
||||
data class MethodDetails(
|
||||
@SerializedName("provider") val provider: String? = null,
|
||||
@SerializedName("providerConfigDetails")
|
||||
val providerConfigDetails: ProviderConfigDetails? = null
|
||||
) {
|
||||
data class ProviderConfigDetails(
|
||||
@SerializedName("upiLink") val upiLink: String? = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2024 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navi.ap.common.models.lambdamodels.response
|
||||
|
||||
import android.os.Parcelable
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
data class AppMetaData(
|
||||
@SerializedName("appPackageName") val appPackageName: String? = null,
|
||||
@SerializedName("appIconUrl") val appIconUrl: String? = null,
|
||||
@SerializedName("appName") val appName: String? = null,
|
||||
) : Parcelable
|
||||
|
||||
data class FilteredUPIAppsResponse(
|
||||
@SerializedName("listOfEnabledApps") val listOfEnabledApps: List<AppMetaData>? = null,
|
||||
@SerializedName("rpdPossible") val rpdPossible: Boolean? = null
|
||||
)
|
||||
@@ -0,0 +1,252 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2024 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navi.ap.common.renderer
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.BoxScope
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.lazy.grid.GridCells
|
||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||
import androidx.compose.foundation.lazy.grid.itemsIndexed
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableIntState
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.navi.ap.common.models.WidgetModelDefinition
|
||||
import com.navi.ap.common.models.customwidget.GridItem
|
||||
import com.navi.ap.common.models.customwidget.GridItemData
|
||||
import com.navi.ap.common.models.customwidget.RadioGroupGridWidgetData
|
||||
import com.navi.ap.common.models.lambdamodels.response.AppMetaData
|
||||
import com.navi.ap.common.viewmodel.ApplicationPlatformVM
|
||||
import com.navi.ap.utils.constants.MAX_SIZE
|
||||
import com.navi.ap.utils.constants.MIN_SIZE
|
||||
import com.navi.ap.utils.constants.WIDGET_DATA
|
||||
import com.navi.uitron.model.UiTronResponse
|
||||
import com.navi.uitron.model.data.ImageData
|
||||
import com.navi.uitron.model.data.TextData
|
||||
import com.navi.uitron.model.data.UiTronActionData
|
||||
import com.navi.uitron.model.ui.ImageProperty
|
||||
import com.navi.uitron.model.ui.TextProperty
|
||||
import com.navi.uitron.render.ImageRenderer
|
||||
import com.navi.uitron.render.TextRenderer
|
||||
import com.navi.uitron.utils.getContentPaddingValues
|
||||
import com.navi.uitron.utils.hexToComposeColor
|
||||
import com.navi.uitron.utils.setVerticalArrangement
|
||||
|
||||
class RadioGroupGridWidget {
|
||||
|
||||
@Composable
|
||||
fun Render(viewModel: ApplicationPlatformVM, widget: WidgetModelDefinition<UiTronResponse>) {
|
||||
|
||||
val widgetData = widget.widgetData?.data
|
||||
val radioGroupGridWidgetData =
|
||||
widgetData?.get("$WIDGET_DATA${widget.widgetId}") as? RadioGroupGridWidgetData
|
||||
|
||||
val listData =
|
||||
viewModel.handle
|
||||
.getStateFlow("${UPI_RADIO_GROUP_DATA}${widget.widgetId}", emptyList<AppMetaData>())
|
||||
.collectAsState()
|
||||
.value
|
||||
|
||||
val gridWidgetData = radioGroupGridWidgetData?.gridData
|
||||
val selectedRadioIndex = remember {
|
||||
mutableIntStateOf(gridWidgetData?.defaultItemSelectedIndex ?: -1)
|
||||
}
|
||||
LazyVerticalGrid(
|
||||
modifier =
|
||||
Modifier.heightIn(
|
||||
gridWidgetData?.minGridSize?.dp ?: MIN_SIZE.dp,
|
||||
gridWidgetData?.maxGridSize?.dp ?: MAX_SIZE.dp
|
||||
),
|
||||
columns = GridCells.Fixed(4),
|
||||
contentPadding = getContentPaddingValues(gridWidgetData?.padding),
|
||||
verticalArrangement =
|
||||
Arrangement.setVerticalArrangement(
|
||||
arrangementData = gridWidgetData?.verticalArrangementData
|
||||
)
|
||||
) {
|
||||
itemsIndexed(listData) { index, item ->
|
||||
val isSelected = index == selectedRadioIndex.intValue
|
||||
GridItem(
|
||||
radioGroupGridWidgetData?.itemProperties,
|
||||
radioGroupGridWidgetData?.itemData,
|
||||
selectedRadioIndex,
|
||||
index,
|
||||
item,
|
||||
isSelected,
|
||||
radioGroupGridWidgetData?.selectedAction,
|
||||
viewModel
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun GridItem(
|
||||
itemProperty: GridItem?,
|
||||
itemData: GridItemData?,
|
||||
selectedRadioIndex: MutableIntState,
|
||||
index: Int,
|
||||
item: Any?,
|
||||
isSelected: Boolean,
|
||||
selectedAction: UiTronActionData?,
|
||||
viewModel: ApplicationPlatformVM
|
||||
) {
|
||||
item as AppMetaData
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
UpiItem(
|
||||
selectedRadioIndex,
|
||||
index,
|
||||
isSelected,
|
||||
itemProperty,
|
||||
item,
|
||||
itemData,
|
||||
selectedAction,
|
||||
viewModel
|
||||
)
|
||||
Spacer(modifier = Modifier.height(itemProperty?.spaceBetweenImageAndText?.dp ?: 0.dp))
|
||||
TitleText(itemProperty, item, viewModel)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun UpiItem(
|
||||
selectedRadioIndex: MutableIntState,
|
||||
index: Int,
|
||||
isSelected: Boolean,
|
||||
itemProperty: GridItem?,
|
||||
item: Any?,
|
||||
itemData: GridItemData?,
|
||||
selectedAction: UiTronActionData?,
|
||||
viewModel: ApplicationPlatformVM
|
||||
) {
|
||||
item as AppMetaData
|
||||
Box {
|
||||
UpiIcon(
|
||||
isSelected,
|
||||
itemProperty,
|
||||
item,
|
||||
viewModel,
|
||||
Modifier.clickable(
|
||||
indication = null,
|
||||
interactionSource = remember { MutableInteractionSource() }
|
||||
) {
|
||||
selectedRadioIndex.intValue = index
|
||||
viewModel.handle[SELECTED_PACKAGE_NAME_KEY] = item.appPackageName
|
||||
viewModel.handle[SELECTED_APP_NAME_KEY] = item.appName
|
||||
viewModel.handleActions(selectedAction)
|
||||
}
|
||||
)
|
||||
UpiItemSelectedIcon(isSelected, itemProperty, itemData, viewModel)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TitleText(
|
||||
itemProperty: GridItem?,
|
||||
item: AppMetaData,
|
||||
viewModel: ApplicationPlatformVM
|
||||
) {
|
||||
TextRenderer()
|
||||
.Render(
|
||||
property = itemProperty?.titleTextProperty ?: TextProperty(),
|
||||
uiTronData = TextData(item.appName),
|
||||
uiTronViewModel = viewModel,
|
||||
modifier = Modifier
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BoxScope.UpiItemSelectedIcon(
|
||||
isSelected: Boolean,
|
||||
itemProperty: GridItem?,
|
||||
itemData: GridItemData?,
|
||||
viewModel: ApplicationPlatformVM
|
||||
) {
|
||||
if (isSelected)
|
||||
ImageRenderer()
|
||||
.Render(
|
||||
property = itemProperty?.selectedImageProperty ?: ImageProperty(),
|
||||
uiTronData = itemData?.selectedImageData,
|
||||
uiTronViewModel = viewModel,
|
||||
modifier =
|
||||
upiItemSelectedIconModifier(
|
||||
itemProperty?.selectedImageProperty?.width?.toFloat()?.div(4) ?: 0f,
|
||||
itemProperty?.selectedImageProperty?.height?.toFloat()?.div(4) ?: 0f,
|
||||
Alignment.TopEnd
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@SuppressLint("ModifierFactoryExtensionFunction")
|
||||
private fun BoxScope.upiItemSelectedIconModifier(
|
||||
translateX: Float,
|
||||
translateY: Float,
|
||||
alignment: Alignment
|
||||
): Modifier {
|
||||
return Modifier.align(alignment).graphicsLayer {
|
||||
translationX = translateX
|
||||
translationY = -translateY
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun UpiIcon(
|
||||
isSelected: Boolean,
|
||||
itemProperty: GridItem?,
|
||||
item: Any?,
|
||||
viewModel: ApplicationPlatformVM,
|
||||
modifier: Modifier
|
||||
) {
|
||||
item as AppMetaData
|
||||
val selectedColor =
|
||||
itemProperty?.mainImageProperty?.backgroundColor?.hexToComposeColor ?: Color(0xff1f002a)
|
||||
val unselectedColor =
|
||||
itemProperty?.mainImageProperty?.backgroundColor?.hexToComposeColor ?: Color(0xffF0F0F0)
|
||||
Column(
|
||||
modifier =
|
||||
modifier.border(
|
||||
width = 1.dp,
|
||||
color = if (isSelected) selectedColor else unselectedColor,
|
||||
shape = RoundedCornerShape(8.dp)
|
||||
)
|
||||
) {
|
||||
ImageRenderer()
|
||||
.Render(
|
||||
property = itemProperty?.mainImageProperty ?: ImageProperty(),
|
||||
uiTronData = ImageData(item.appIconUrl),
|
||||
uiTronViewModel = viewModel,
|
||||
modifier = Modifier
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val UPI_RADIO_GROUP_DATA = "upi_radio_group_data_"
|
||||
const val SELECTED_PACKAGE_NAME_KEY = "rpd.selectedUpiAppPackageName"
|
||||
const val SELECTED_APP_NAME_KEY = "rpd.selectedUpiAppName"
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ import com.navi.ap.common.models.customwidget.DynamicGridWidgetData
|
||||
import com.navi.ap.common.models.customwidget.DynamicRadioGroupWithSectionsWidgetData
|
||||
import com.navi.ap.common.models.customwidget.DynamicRowWidgetData
|
||||
import com.navi.ap.common.models.customwidget.MappedRadioListWidgetData
|
||||
import com.navi.ap.common.models.customwidget.RadioGroupGridWidgetData
|
||||
import com.navi.ap.common.models.customwidget.StepTrackerWidgetData
|
||||
import com.navi.uitron.model.data.UiTronData
|
||||
import com.navi.uitron.serializer.UiTronDataSerializer
|
||||
@@ -73,6 +74,12 @@ class CustomUiTronDataSerializer : UiTronDataSerializer() {
|
||||
CustomWidgets.CALENDAR_WIDGET.name -> {
|
||||
context?.serialize(src as CalendarWidgetData, CalendarWidgetData::class.java)
|
||||
}
|
||||
CustomWidgets.RADIO_GROUP_GRID_WIDGET.name -> {
|
||||
context?.serialize(
|
||||
src as RadioGroupGridWidgetData,
|
||||
RadioGroupGridWidgetData::class.java
|
||||
)
|
||||
}
|
||||
else -> super.serialize(src, typeOfSrc, context)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import com.navi.ap.common.renderer.DynamicGridWidget
|
||||
import com.navi.ap.common.renderer.DynamicRadioGroupWithSectionsWidget
|
||||
import com.navi.ap.common.renderer.DynamicRowWidget
|
||||
import com.navi.ap.common.renderer.MappedRadioListWidget
|
||||
import com.navi.ap.common.renderer.RadioGroupGridWidget
|
||||
import com.navi.ap.common.renderer.StepTrackerWidget
|
||||
import com.navi.ap.common.viewmodel.ApplicationPlatformVM
|
||||
import com.navi.uitron.model.UiTronResponse
|
||||
@@ -60,6 +61,9 @@ fun CustomWidgetRenderer(
|
||||
CustomWidgets.CALENDAR_WIDGET.name -> {
|
||||
CalendarWidget().Render(viewModel = viewModel, widget = widget)
|
||||
}
|
||||
CustomWidgets.RADIO_GROUP_GRID_WIDGET.name -> {
|
||||
RadioGroupGridWidget().Render(viewModel = viewModel, widget = widget)
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,11 +14,14 @@ import com.navi.ap.common.models.lambdamodels.RPDTokenData
|
||||
import com.navi.ap.common.models.lambdamodels.RPDTokenRequestDetails
|
||||
import com.navi.ap.common.models.lambdamodels.request.EmiModel
|
||||
import com.navi.ap.common.models.lambdamodels.request.FetchPaymentMethodsRequest
|
||||
import com.navi.ap.common.models.lambdamodels.request.InstalledUpiApps
|
||||
import com.navi.ap.common.models.lambdamodels.request.OfferDetails
|
||||
import com.navi.ap.common.models.lambdamodels.request.RPDPaymentData
|
||||
import com.navi.ap.common.models.lambdamodels.request.TelcoResendOtpRequest
|
||||
import com.navi.ap.common.models.lambdamodels.response.AgreementLetterDownloadResponse
|
||||
import com.navi.ap.common.models.lambdamodels.response.ApplyLoanResponse
|
||||
import com.navi.ap.common.models.lambdamodels.response.BankDataResponse
|
||||
import com.navi.ap.common.models.lambdamodels.response.FilteredUPIAppsResponse
|
||||
import com.navi.ap.common.models.lambdamodels.response.IfscBranchResponse
|
||||
import com.navi.ap.common.models.lambdamodels.response.KYCTrackerItemsListData
|
||||
import com.navi.ap.common.models.lambdamodels.response.KycSdkVerificationResponse
|
||||
@@ -106,6 +109,25 @@ interface PlLambdaService {
|
||||
@Path("methodId") methodId: String
|
||||
): Response<GenericResponse<RPDPaymentMethodDetails>>
|
||||
|
||||
@POST("/payment-methods")
|
||||
suspend fun sendUPIApps(
|
||||
@Body data: InstalledUpiApps,
|
||||
@Header("X-Target") target: String
|
||||
): Response<GenericResponse<FilteredUPIAppsResponse>>
|
||||
|
||||
@POST("/api/v2/get-methods")
|
||||
suspend fun fetchRPDPaymentDetails(
|
||||
@Header("X-Target") target: String,
|
||||
@Header("X-Payment-SDK-Token") token: String,
|
||||
@Header("X-Payment-SDK-Version") version: String = Constants.PAYMENT_SDK_VERSION
|
||||
): Response<GenericResponse<RPDPaymentData>>
|
||||
|
||||
@POST("api/v1/signal/v2/checkStatus")
|
||||
suspend fun postRPDStatus(
|
||||
@Header("X-Target") target: String,
|
||||
@Header("X-Payment-SDK-Token") token: String
|
||||
): Response<GenericResponse<Any>>
|
||||
|
||||
@GET("/banks/{code}")
|
||||
suspend fun validateIFSC(
|
||||
@Header("X-Target") target: String = ModuleName.LE.name,
|
||||
|
||||
@@ -45,6 +45,7 @@ import com.navi.common.uitron.model.action.FillApiData
|
||||
import com.navi.common.uitron.model.action.SourceType
|
||||
import com.navi.common.utils.CommonUtils
|
||||
import com.navi.common.utils.EMPTY
|
||||
import com.navi.common.utils.getDeviceData
|
||||
import com.navi.common.utils.log
|
||||
import com.navi.uitron.model.UiTronResponse
|
||||
import com.navi.uitron.utils.getInputId
|
||||
@@ -184,6 +185,15 @@ fun getResolvedFieldValue(
|
||||
val output = readJsonPath(obj.toJson(), item.jsonPath.orEmpty())
|
||||
map[item.sourceProperty.orEmpty()] = "$output$valueSuffix"
|
||||
}
|
||||
SourceType.DEVICE_PROPERTY.name -> {
|
||||
val value =
|
||||
getDeviceData(
|
||||
sourceProperty = item.sourceProperty.orEmpty(),
|
||||
context = CommonLibManager.application.applicationContext,
|
||||
additionalValues = item.additionalParameters
|
||||
)
|
||||
map[item.name.orEmpty()] = value
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,9 @@ enum class LambdaType {
|
||||
APPLY_LOAN,
|
||||
FETCH_RPD_TOKEN,
|
||||
FETCH_RPD_PAYMENT_METHOD_DETAILS,
|
||||
FETCH_FILTERED_UPI_APPS,
|
||||
FETCH_RPD_PAYMENT_DETAILS,
|
||||
POST_RPD_STATUS,
|
||||
FETCH_CONSENT_DATA,
|
||||
FETCH_BANKS,
|
||||
VALIDATE_IFSC,
|
||||
|
||||
@@ -25,6 +25,8 @@ const val FINARKEIN_CONSENT_DATA = "finarkein_consent_data"
|
||||
const val RPD_PAYMENT_METHOD_TOKEN = "rpdPaymentMethodToken"
|
||||
const val RPD_PAYMENT_METHOD_ID = "rpdPaymentMethodId"
|
||||
const val RPD_PAYMENT_METHOD_UPI_LINK_KEY = "upiLink"
|
||||
const val PREFERRED_UPI_APPS_LIST = "preferred_upi_apps_list"
|
||||
const val RPD_PAYMENT_URI = "rpd_payment_uri_link_key"
|
||||
|
||||
const val ALL_BANKS_LIST = "all_banks_list"
|
||||
const val PREFERRED_BANKS_LIST = "preferred_banks_list"
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
package com.navi.base.utils
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
@@ -558,4 +559,18 @@ object BaseUtils {
|
||||
val timeStamp: String = SimpleDateFormat(datePattern, Locale.getDefault()).format(Date())
|
||||
return File(storageDir, "JPEG_${timeStamp}.jpg")
|
||||
}
|
||||
|
||||
@SuppressLint("QueryPermissionsNeeded")
|
||||
fun getUPIAppsInstalledOnDevice(activity: Context): List<String> {
|
||||
val packageManager = activity.packageManager
|
||||
val intent = Intent(Intent.ACTION_VIEW)
|
||||
intent.data = Uri.parse(UPI_APP_INTENT_URL)
|
||||
val activities =
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
packageManager.queryIntentActivities(intent, PackageManager.MATCH_ALL)
|
||||
} else {
|
||||
packageManager.queryIntentActivities(intent, INT_ZERO)
|
||||
}
|
||||
return activities.map { it.activityInfo.packageName }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import com.google.gson.JsonElement
|
||||
import com.navi.common.uitron.model.action.LaunchDefaultIntentAction
|
||||
import com.navi.common.uitron.model.action.LaunchIntentAction
|
||||
import com.navi.common.uitron.model.action.LaunchIntentType
|
||||
import com.navi.common.uitron.model.action.LaunchTargetAppIntentAction
|
||||
import java.lang.reflect.Type
|
||||
|
||||
class UiTronLaunchIntentActionDeserializer : JsonDeserializer<LaunchIntentAction> {
|
||||
@@ -27,6 +28,8 @@ class UiTronLaunchIntentActionDeserializer : JsonDeserializer<LaunchIntentAction
|
||||
return when (type.asString) {
|
||||
LaunchIntentType.DEFAULT.name ->
|
||||
context?.deserialize(jsonObject, LaunchDefaultIntentAction::class.java)
|
||||
LaunchIntentType.OPEN_TARGET_APP.name ->
|
||||
context?.deserialize(jsonObject, LaunchTargetAppIntentAction::class.java)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,8 @@ open class LaunchIntentAction(
|
||||
@SerializedName("intentUriString") val intentUriString: FillApiData? = null,
|
||||
@SerializedName("onSuccess") val onSuccess: UiTronActionData? = null,
|
||||
@SerializedName("onFailure") val onFailure: UiTronActionData? = null,
|
||||
@SerializedName("onExit") val onExit: UiTronActionData? = null
|
||||
@SerializedName("onExit") val onExit: UiTronActionData? = null,
|
||||
@SerializedName("onInitiateFailure") val onInitiateFailure: UiTronActionData? = null,
|
||||
) : UiTronAction(), Parcelable {
|
||||
override suspend fun manageAction(actionDetails: ActionDetails) {
|
||||
val action = actionDetails.uiTronAction as LaunchIntentAction
|
||||
@@ -31,6 +32,11 @@ open class LaunchIntentAction(
|
||||
|
||||
class LaunchDefaultIntentAction : LaunchIntentAction()
|
||||
|
||||
class LaunchTargetAppIntentAction(
|
||||
@SerializedName("targetAppPackageName") val targetAppPackageName: String? = null,
|
||||
) : LaunchIntentAction()
|
||||
|
||||
enum class LaunchIntentType {
|
||||
DEFAULT
|
||||
DEFAULT,
|
||||
OPEN_TARGET_APP
|
||||
}
|
||||
|
||||
@@ -232,6 +232,7 @@ object Constants {
|
||||
const val CONTENT_SIZE_IN_KB = "content_size_kb"
|
||||
const val API_METRIC_EVENT = "dev_api_metric_event"
|
||||
const val IS_UPI_APP_AVAILABLE = "isUpiAppAvailable"
|
||||
const val LIST_OF_INSTALLED_UPI_APPS = "LIST_OF_INSTALLED_UPI_APPS"
|
||||
const val ANIMATION_DURATION_IN_MILLIS = 400
|
||||
const val EIGHT = 8
|
||||
const val FINISH = "finish"
|
||||
|
||||
@@ -9,16 +9,18 @@ package com.navi.common.utils
|
||||
|
||||
import android.content.Context
|
||||
import com.navi.base.model.LineItem
|
||||
import com.navi.base.utils.BaseUtils.getUPIAppsInstalledOnDevice
|
||||
import com.navi.base.utils.BaseUtils.isUpiAppExceptParticularAppsAvailable
|
||||
import com.navi.common.constants.DEVICE_ID
|
||||
import com.navi.common.utils.Constants.IS_DEVICE_ROOTED
|
||||
import com.navi.common.utils.Constants.IS_UPI_APP_AVAILABLE
|
||||
import com.navi.common.utils.Constants.LIST_OF_INSTALLED_UPI_APPS
|
||||
|
||||
fun getDeviceData(
|
||||
sourceProperty: String,
|
||||
context: Context,
|
||||
additionalValues: List<LineItem>?
|
||||
): String {
|
||||
): Any {
|
||||
return when (sourceProperty) {
|
||||
DEVICE_ID -> deviceId
|
||||
IS_DEVICE_ROOTED -> CommonRootDeviceUtil.instance.isDeviceRooted().toString()
|
||||
@@ -28,6 +30,7 @@ fun getDeviceData(
|
||||
exceptionUpiApps = additionalValues?.map { it.value.orEmpty() }.orEmpty()
|
||||
)
|
||||
.toString()
|
||||
LIST_OF_INSTALLED_UPI_APPS -> getUPIAppsInstalledOnDevice(context)
|
||||
else -> EMPTY
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user