From bf705b0900574b130a94e7b9f040c4c7bbc9c823 Mon Sep 17 00:00:00 2001 From: Anmol Agrawal Date: Wed, 27 Mar 2024 11:31:12 +0530 Subject: [PATCH] TP-56773 reverse penny drop in PL journey (#10149) Co-authored-by: soumya-ranjan_navi --- .../CustomUiTronDataDeserializer.kt | 3 + .../handler/LaunchIntentActionHandler.kt | 30 ++- .../verticals/personalloan/PLLambdaHandler.kt | 12 + .../verticals/personalloan/PLLambdaImpl.kt | 154 +++++++++++ .../personalloan/PLLambdaRepository.kt | 31 +++ .../com/navi/ap/common/models/WidgetModel.kt | 1 + .../customwidget/RadioGroupGridWidgetData.kt | 46 ++++ .../lambdamodels/request/InstalledUpiApps.kt | 15 ++ .../lambdamodels/request/RPDPaymentData.kt | 26 ++ .../response/UpiAppDataResponse.kt | 24 ++ .../common/renderer/RadioGroupGridWidget.kt | 252 ++++++++++++++++++ .../serializer/CustomUiTronDataSerializer.kt | 7 + .../widgetfactory/CustomWidgetRenderer.kt | 4 + .../retrofit/service/PlLambdaService.kt | 22 ++ .../main/kotlin/com/navi/ap/utils/Utils.kt | 10 + .../navi/ap/utils/constants/EnumsConstant.kt | 3 + .../ap/utils/constants/LambdaConstants.kt | 2 + .../java/com/navi/base/utils/BaseUtils.kt | 15 ++ .../UiTronLaunchIntentActionDeserializer.kt | 3 + .../uitron/model/action/LaunchIntentAction.kt | 10 +- .../java/com/navi/common/utils/Constants.kt | 1 + .../com/navi/common/utils/DeviceDataUtil.kt | 5 +- 22 files changed, 672 insertions(+), 4 deletions(-) create mode 100644 application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/models/customwidget/RadioGroupGridWidgetData.kt create mode 100644 application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/models/lambdamodels/request/InstalledUpiApps.kt create mode 100644 application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/models/lambdamodels/request/RPDPaymentData.kt create mode 100644 application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/models/lambdamodels/response/UpiAppDataResponse.kt create mode 100644 application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/renderer/RadioGroupGridWidget.kt diff --git a/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/deserializer/CustomUiTronDataDeserializer.kt b/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/deserializer/CustomUiTronDataDeserializer.kt index 3ecb0def8e..3d929e87f4 100644 --- a/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/deserializer/CustomUiTronDataDeserializer.kt +++ b/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/deserializer/CustomUiTronDataDeserializer.kt @@ -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) } } diff --git a/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/handler/LaunchIntentActionHandler.kt b/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/handler/LaunchIntentActionHandler.kt index b534bd4359..4a37799c38 100644 --- a/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/handler/LaunchIntentActionHandler.kt +++ b/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/handler/LaunchIntentActionHandler.kt @@ -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 -> {} } } diff --git a/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/lambda/verticals/personalloan/PLLambdaHandler.kt b/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/lambda/verticals/personalloan/PLLambdaHandler.kt index 7f83307338..987939cc14 100644 --- a/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/lambda/verticals/personalloan/PLLambdaHandler.kt +++ b/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/lambda/verticals/personalloan/PLLambdaHandler.kt @@ -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(), diff --git a/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/lambda/verticals/personalloan/PLLambdaImpl.kt b/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/lambda/verticals/personalloan/PLLambdaImpl.kt index 30a27173e4..c17fc1b571 100644 --- a/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/lambda/verticals/personalloan/PLLambdaImpl.kt +++ b/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/lambda/verticals/personalloan/PLLambdaImpl.kt @@ -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, + 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() + .injectData( + lambdaHandler.getClonedScreenDefinitionState(), + lambdaResponse.data + ) + val updatedLambdaApiAction = + PathInjector() + .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(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(RPD_PAYMENT_METHOD_TOKEN).orEmpty() + val lambdaResponse = repository.postRPDStatus(token = token) + bridge.setLambdaState( + when { + lambdaResponse.data.isNotNull() -> { + val updatedLambdaApiAction = + PathInjector() + .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, diff --git a/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/lambda/verticals/personalloan/PLLambdaRepository.kt b/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/lambda/verticals/personalloan/PLLambdaRepository.kt index e76b5568c4..1b70855bae 100644 --- a/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/lambda/verticals/personalloan/PLLambdaRepository.kt +++ b/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/lambda/verticals/personalloan/PLLambdaRepository.kt @@ -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 { + 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 { + 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 { + 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 { val response = retrofitService.validateIFSC(ifscCode = ifscCode) logApiResponseEvents(methodName = ::validateIFSC.name, response = response) diff --git a/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/models/WidgetModel.kt b/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/models/WidgetModel.kt index 758a4c7b1f..9e4eee6b3b 100644 --- a/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/models/WidgetModel.kt +++ b/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/models/WidgetModel.kt @@ -55,4 +55,5 @@ enum class CustomWidgets { DYNAMIC_RADIO_GROUP_WITH_SECTIONS_WIDGET, CAMERA, CALENDAR_WIDGET, + RADIO_GROUP_GRID_WIDGET } diff --git a/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/models/customwidget/RadioGroupGridWidgetData.kt b/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/models/customwidget/RadioGroupGridWidgetData.kt new file mode 100644 index 0000000000..9dd6f409cf --- /dev/null +++ b/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/models/customwidget/RadioGroupGridWidgetData.kt @@ -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 +) diff --git a/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/models/lambdamodels/request/InstalledUpiApps.kt b/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/models/lambdamodels/request/InstalledUpiApps.kt new file mode 100644 index 0000000000..d0b57a2f2d --- /dev/null +++ b/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/models/lambdamodels/request/InstalledUpiApps.kt @@ -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 +) diff --git a/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/models/lambdamodels/request/RPDPaymentData.kt b/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/models/lambdamodels/request/RPDPaymentData.kt new file mode 100644 index 0000000000..ed4dc5e9d1 --- /dev/null +++ b/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/models/lambdamodels/request/RPDPaymentData.kt @@ -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, + ) + } +} diff --git a/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/models/lambdamodels/response/UpiAppDataResponse.kt b/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/models/lambdamodels/response/UpiAppDataResponse.kt new file mode 100644 index 0000000000..30ccd83ca8 --- /dev/null +++ b/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/models/lambdamodels/response/UpiAppDataResponse.kt @@ -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? = null, + @SerializedName("rpdPossible") val rpdPossible: Boolean? = null +) diff --git a/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/renderer/RadioGroupGridWidget.kt b/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/renderer/RadioGroupGridWidget.kt new file mode 100644 index 0000000000..c8240e7d9c --- /dev/null +++ b/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/renderer/RadioGroupGridWidget.kt @@ -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) { + + 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()) + .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" + } +} diff --git a/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/serializer/CustomUiTronDataSerializer.kt b/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/serializer/CustomUiTronDataSerializer.kt index 1dd3d59e74..a8337257be 100644 --- a/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/serializer/CustomUiTronDataSerializer.kt +++ b/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/serializer/CustomUiTronDataSerializer.kt @@ -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) } } diff --git a/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/widgetfactory/CustomWidgetRenderer.kt b/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/widgetfactory/CustomWidgetRenderer.kt index 888a9159ec..29e9d57d42 100644 --- a/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/widgetfactory/CustomWidgetRenderer.kt +++ b/application-platform/navi-ap/src/main/kotlin/com/navi/ap/common/widgetfactory/CustomWidgetRenderer.kt @@ -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 } } diff --git a/application-platform/navi-ap/src/main/kotlin/com/navi/ap/network/retrofit/service/PlLambdaService.kt b/application-platform/navi-ap/src/main/kotlin/com/navi/ap/network/retrofit/service/PlLambdaService.kt index d0f6d98fe4..6347965eaa 100644 --- a/application-platform/navi-ap/src/main/kotlin/com/navi/ap/network/retrofit/service/PlLambdaService.kt +++ b/application-platform/navi-ap/src/main/kotlin/com/navi/ap/network/retrofit/service/PlLambdaService.kt @@ -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> + @POST("/payment-methods") + suspend fun sendUPIApps( + @Body data: InstalledUpiApps, + @Header("X-Target") target: String + ): Response> + + @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> + + @POST("api/v1/signal/v2/checkStatus") + suspend fun postRPDStatus( + @Header("X-Target") target: String, + @Header("X-Payment-SDK-Token") token: String + ): Response> + @GET("/banks/{code}") suspend fun validateIFSC( @Header("X-Target") target: String = ModuleName.LE.name, diff --git a/application-platform/navi-ap/src/main/kotlin/com/navi/ap/utils/Utils.kt b/application-platform/navi-ap/src/main/kotlin/com/navi/ap/utils/Utils.kt index eabb0a1ed1..3bdf187f04 100644 --- a/application-platform/navi-ap/src/main/kotlin/com/navi/ap/utils/Utils.kt +++ b/application-platform/navi-ap/src/main/kotlin/com/navi/ap/utils/Utils.kt @@ -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 } } diff --git a/application-platform/navi-ap/src/main/kotlin/com/navi/ap/utils/constants/EnumsConstant.kt b/application-platform/navi-ap/src/main/kotlin/com/navi/ap/utils/constants/EnumsConstant.kt index c12c0ed8d5..731cb8299f 100644 --- a/application-platform/navi-ap/src/main/kotlin/com/navi/ap/utils/constants/EnumsConstant.kt +++ b/application-platform/navi-ap/src/main/kotlin/com/navi/ap/utils/constants/EnumsConstant.kt @@ -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, diff --git a/application-platform/navi-ap/src/main/kotlin/com/navi/ap/utils/constants/LambdaConstants.kt b/application-platform/navi-ap/src/main/kotlin/com/navi/ap/utils/constants/LambdaConstants.kt index bd6532a22d..b4eff0eaa9 100644 --- a/application-platform/navi-ap/src/main/kotlin/com/navi/ap/utils/constants/LambdaConstants.kt +++ b/application-platform/navi-ap/src/main/kotlin/com/navi/ap/utils/constants/LambdaConstants.kt @@ -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" diff --git a/navi-base/src/main/java/com/navi/base/utils/BaseUtils.kt b/navi-base/src/main/java/com/navi/base/utils/BaseUtils.kt index f5551c19cd..bedfade1e5 100644 --- a/navi-base/src/main/java/com/navi/base/utils/BaseUtils.kt +++ b/navi-base/src/main/java/com/navi/base/utils/BaseUtils.kt @@ -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 { + 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 } + } } diff --git a/navi-common/src/main/java/com/navi/common/uitron/deserializer/UiTronLaunchIntentActionDeserializer.kt b/navi-common/src/main/java/com/navi/common/uitron/deserializer/UiTronLaunchIntentActionDeserializer.kt index 6616eec80e..093e5d7dd7 100644 --- a/navi-common/src/main/java/com/navi/common/uitron/deserializer/UiTronLaunchIntentActionDeserializer.kt +++ b/navi-common/src/main/java/com/navi/common/uitron/deserializer/UiTronLaunchIntentActionDeserializer.kt @@ -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 { @@ -27,6 +28,8 @@ class UiTronLaunchIntentActionDeserializer : JsonDeserializer context?.deserialize(jsonObject, LaunchDefaultIntentAction::class.java) + LaunchIntentType.OPEN_TARGET_APP.name -> + context?.deserialize(jsonObject, LaunchTargetAppIntentAction::class.java) else -> null } } diff --git a/navi-common/src/main/java/com/navi/common/uitron/model/action/LaunchIntentAction.kt b/navi-common/src/main/java/com/navi/common/uitron/model/action/LaunchIntentAction.kt index e35b237de9..5d2e83bbbd 100644 --- a/navi-common/src/main/java/com/navi/common/uitron/model/action/LaunchIntentAction.kt +++ b/navi-common/src/main/java/com/navi/common/uitron/model/action/LaunchIntentAction.kt @@ -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 } diff --git a/navi-common/src/main/java/com/navi/common/utils/Constants.kt b/navi-common/src/main/java/com/navi/common/utils/Constants.kt index 9ed5965178..0870a2f3e4 100644 --- a/navi-common/src/main/java/com/navi/common/utils/Constants.kt +++ b/navi-common/src/main/java/com/navi/common/utils/Constants.kt @@ -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" diff --git a/navi-common/src/main/java/com/navi/common/utils/DeviceDataUtil.kt b/navi-common/src/main/java/com/navi/common/utils/DeviceDataUtil.kt index f53235240d..aded1367cd 100644 --- a/navi-common/src/main/java/com/navi/common/utils/DeviceDataUtil.kt +++ b/navi-common/src/main/java/com/navi/common/utils/DeviceDataUtil.kt @@ -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? -): 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 } }