NTP-75220 | decentro integration (#16683)

This commit is contained in:
Sandeep Kumar
2025-06-22 08:40:03 +05:30
committed by GitHub
parent 2c25041e84
commit aa2ca256f6
7 changed files with 287 additions and 0 deletions

View File

@@ -92,6 +92,12 @@
android:screenOrientation="portrait"
android:theme="@style/GiAppThemeWhiteStatusBar" />
<activity
android:name=".decentro.GiWebViewActivity"
android:exported="false"
android:screenOrientation="portrait"
android:theme="@style/GiAppThemeWhiteStatusBar" />
<activity
android:name=".health.activity.AbhaContainerActivity"
android:exported="false"

View File

@@ -476,6 +476,12 @@ object InsuranceAnalyticsConstants {
const val HI_HRC_FullReport_Land_Success = "HI_HRC_FullReport_Land_Success"
const val HI_Health_Score = "HI_Health_Score"
const val HI_DECENTRO_KYC_SCREEN_LAND = "hi_decentro_kyc_screen_land"
const val HI_DECENTRO_KYC_WEBVIEW_INIT = "hi_decentro_kyc_webview_init"
const val HI_DECENTRO_KYC_NAVIGATION_LISTENER = "hi_decentro_kyc_navigation_listener"
const val HI_DECENTRO_KYC_EXIT_DETECTED = "hi_decentro_kyc_exit_detected"
const val HI_DECENTRO_TIMEOUT_ERROR = "hi_decentro_timeout_error"
// Free Insurance
const val FREE_INSURANCE_CONTAINER = "free_insurance_container"
const val FREE_INSURANCE_CALENDAR_SCREEN = "free_insurance_calendar"

View File

@@ -355,6 +355,7 @@ class NavigationHandler @Inject constructor(private val uiControllerUtil: UiCont
const val URL_HI_QUIZ_QUESTION_SCREEN = "hi_quiz_question_screen"
const val URL_HI_QUIZ_RESULT_SCREEN = "hi_quiz_result_screen"
const val URL_INSURANCE_CONTAINER = "insurance_container"
const val URL_DECENTRO = "decentro"
const val URL_ABHA_CONTAINER = "abha_container"
const val URL_KYC_ACTIVITY = "kyc_activity"
const val URL_FREE_INSURANCE_PAYMENT = "fi_payment"

View File

@@ -0,0 +1,125 @@
/*
*
* * Copyright © 2025 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
package com.navi.insurance.decentro
import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.lifecycle.lifecycleScope
import com.google.gson.Gson
import com.navi.base.model.CtaData
import com.navi.insurance.analytics.InsuranceAnalyticsConstants
import com.navi.insurance.analytics.NaviInsuranceAnalytics
import com.navi.insurance.common.GiBaseActivity
import com.navi.insurance.common.theme.color.GiMaterialTheme
import com.navi.insurance.navigator.NaviInsuranceDeeplinkNavigator
import com.navi.insurance.util.Constants
import com.navi.insurance.util.Constants.DECENTRO_KYC_SCREEN
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
@AndroidEntryPoint
class GiWebViewActivity : GiBaseActivity() {
private lateinit var ctaData: CtaData
private var timeoutThresholdMs: Long = 0
private var timeoutJob: Job? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
sendEvent(InsuranceAnalyticsConstants.HI_DECENTRO_KYC_SCREEN_LAND)
val webUrl = intent.getStringExtra(WEB_URL)
val exitUrl = intent.getStringExtra(WEBVIEW_EXIT_URL)
timeoutThresholdMs = intent.getStringExtra(CLOSE_TIMEOUT)?.toLong() ?: 0
ctaData = Gson().fromJson(intent.getStringExtra(CTA_DATA).orEmpty(), CtaData::class.java)
enableEdgeToEdge()
startTimeout()
setContent {
GiMaterialTheme {
WebViewScreen(
url = webUrl.orEmpty(),
exitUrl = exitUrl.orEmpty(),
nextScreen = { nextScreen() },
sendEvent = ::sendEvent,
)
}
}
}
override fun onPause() {
cancelTimeout()
super.onPause()
}
override fun onResume() {
super.onResume()
if (timeoutThresholdMs > 0) {
startTimeout()
}
}
override fun onDestroy() {
cancelTimeout()
super.onDestroy()
}
override fun onBackPressed() {
super.onBackPressed()
nextScreen()
}
private fun startTimeout() {
if (timeoutThresholdMs > 0) {
cancelTimeout()
val exceptionHandler = CoroutineExceptionHandler { _, _ ->
sendEvent(InsuranceAnalyticsConstants.HI_DECENTRO_TIMEOUT_ERROR)
}
timeoutJob =
lifecycleScope.launch(exceptionHandler) {
delay(timeoutThresholdMs)
nextScreen()
}
}
}
private fun cancelTimeout() {
timeoutJob?.cancel()
timeoutJob = null
}
private fun nextScreen() {
val bundle = Bundle()
bundle.putParcelable(Constants.PARAMS_EXTRA, ctaData)
sendEvent(InsuranceAnalyticsConstants.HI_DECENTRO_KYC_EXIT_DETECTED)
NaviInsuranceDeeplinkNavigator.navigate(
activity = this,
ctaData = ctaData,
bundle = bundle,
finish = true,
)
}
private fun sendEvent(eventName: String) {
NaviInsuranceAnalytics.postAnalyticsEvent(
eventName = eventName,
eventProperties = mapOf(Pair(NaviInsuranceAnalytics.SCREEN, DECENTRO_KYC_SCREEN)),
)
}
override val screenName: String
get() = "GiWebViewActivity"
companion object {
const val WEB_URL = "webUrl"
const val WEBVIEW_EXIT_URL = "webviewExitUrl"
const val CLOSE_TIMEOUT = "webviewForceCloseTimeout"
const val CTA_DATA = "CtaData"
}
}

View File

@@ -0,0 +1,143 @@
/*
*
* * Copyright © 2025 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
package com.navi.insurance.decentro
import android.annotation.SuppressLint
import android.graphics.Bitmap
import android.view.ViewGroup
import android.webkit.*
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Close
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import com.navi.insurance.analytics.InsuranceAnalyticsConstants
@SuppressLint("SetJavaScriptEnabled")
@Composable
fun WebViewScreen(
url: String,
exitUrl: String,
nextScreen: () -> Unit = {},
sendEvent: (String) -> Unit = {},
) {
Surface(modifier = Modifier.fillMaxSize()) {
Box(modifier = Modifier.fillMaxSize().padding(top = 32.dp)) {
LaunchedEffect(Unit) {
sendEvent(InsuranceAnalyticsConstants.HI_DECENTRO_KYC_WEBVIEW_INIT)
}
AndroidView(
factory = { ctx ->
WebView(ctx).apply {
layoutParams =
ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT,
)
webViewClient =
object : WebViewClient() {
override fun onPageStarted(
view: WebView?,
url: String?,
favicon: Bitmap?,
) {
sendEvent(
InsuranceAnalyticsConstants
.HI_DECENTRO_KYC_NAVIGATION_LISTENER
)
super.onPageStarted(view, url, favicon)
url?.let { currentUrl ->
if (shouldExitOnUrl(currentUrl, exitUrl)) {
nextScreen()
}
}
}
override fun shouldOverrideUrlLoading(
view: WebView?,
request: WebResourceRequest?,
): Boolean {
request?.url?.let { uri ->
val urlString = uri.toString()
if (shouldExitOnUrl(urlString, exitUrl)) {
nextScreen()
}
}
return super.shouldOverrideUrlLoading(view, request)
}
}
webChromeClient =
object : WebChromeClient() {
override fun onReceivedTitle(view: WebView?, title: String?) {
super.onReceivedTitle(view, title)
title?.let { pageTitle ->
sendEvent("HI_DECENTRO_" + pageTitle.take(30))
}
}
override fun onConsoleMessage(
consoleMessage: ConsoleMessage?
): Boolean {
return true
}
}
settings.apply {
javaScriptEnabled = true
domStorageEnabled = true
loadWithOverviewMode = true
useWideViewPort = true
builtInZoomControls = true
displayZoomControls = false
mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
setSupportMultipleWindows(true)
javaScriptCanOpenWindowsAutomatically = true
loadsImagesAutomatically = true
cacheMode = WebSettings.LOAD_DEFAULT
}
loadUrl(url)
}
},
update = { webView ->
if (webView.url != url) {
webView.loadUrl(url)
}
},
modifier = Modifier.fillMaxSize(),
)
IconButton(
onClick = { nextScreen() },
modifier = Modifier.align(Alignment.TopStart).padding(top = 16.dp),
) {
Icon(
imageVector = Icons.Default.Close,
contentDescription = "Close",
tint = Color.Black,
)
}
}
}
}
private fun shouldExitOnUrl(currentUrl: String, exitUrl: String): Boolean {
if (exitUrl.isEmpty()) {
return false
}
return currentUrl.contains(exitUrl)
}

View File

@@ -119,6 +119,7 @@ import com.navi.insurance.common.util.NavigationHandler.Companion.URL_PAYMENT_ST
import com.navi.insurance.common.util.NavigationHandler.Companion.URL_POP_UP_SCREEN
import com.navi.insurance.common.util.NavigationHandler.Companion.URL_TELE_HRA_BOTTOM_SHEET
import com.navi.insurance.common.util.NavigationHandler.Companion.URL_UPDATE_PREMIUM_BOTTOMSHEET
import com.navi.insurance.decentro.GiWebViewActivity
import com.navi.insurance.emi_date_change.EmiCalendarActivity
import com.navi.insurance.endorsement.activity.EndorsementActivity
import com.navi.insurance.engagement.health_risk_score.activity.HealthRiskScoreActivity
@@ -657,6 +658,10 @@ object NaviInsuranceDeeplinkNavigator {
intent = Intent(activity, InsuranceContainerActivity::class.java)
bundle.putParcelable(KEY_CTA_DATA, ctaData)
}
NavigationHandler.URL_DECENTRO -> {
intent = Intent(activity, GiWebViewActivity::class.java)
bundle.putParcelable(KEY_CTA_DATA, ctaData)
}
NavigationHandler.URL_ABHA_CONTAINER -> {
intent = Intent(activity, AbhaContainerActivity::class.java)
bundle.putParcelable(KEY_CTA_DATA, ctaData)

View File

@@ -218,6 +218,7 @@ object Constants {
const val URL_TITLE_ICON_DESC_BOTTOM_SHEET = "gi/bottom_sheet/title_icon_desc_bottomsheet"
const val screenName = "screenName"
const val TELE_SALES_LANDING_PAGE = "TELE_SALES_LANDING_PAGE"
const val DECENTRO_KYC_SCREEN = "DECENTRO_KYC_SCREEN"
const val KEY_NOTE_TEXT = "noteText"
const val KEY_NOTE_BACKGROUND_COLOR = "noteBackgroundColor"