NTP-7163 | Temporary changes for screen render time (#14019)

This commit is contained in:
shankar yadav
2024-12-06 16:45:18 +05:30
committed by GitHub
parent ca2e2ae1f1
commit 6124121f31
18 changed files with 157 additions and 33 deletions

View File

@@ -27,7 +27,6 @@ fun InitInvestmentsScreenComponents(
investmentsScreenHelper = investmentsScreenHelper,
bottomNavBarVM = bottomNavBarVM
)
LaunchedEffect(Unit) {
investmentsTabVM.fireEvent(
eventName = InvestmentTabEvents.INVESTMENT_TAB_INIT_LANDING_PAGE.eventName,

View File

@@ -14,6 +14,7 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import com.naviapp.common.viewmodel.BottomNavBarVM
import com.naviapp.home.dashboard.viewmodels.InvestmentsVm
import com.naviapp.utils.Constants.INVESTMENT_TAB_SCREEN_V3
@Composable
fun InitLifeCycleListener(
@@ -26,6 +27,7 @@ fun InitLifeCycleListener(
val observer = LifecycleEventObserver { _, event ->
when (event) {
Lifecycle.Event.ON_RESUME -> {
investmentsTabVM.recordApiStartTime(INVESTMENT_TAB_SCREEN_V3)
investmentsScreenHelper.refreshInvestmentTabScreen(investmentsTabVM)
}
Lifecycle.Event.ON_STOP -> {

View File

@@ -12,6 +12,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.navi.common.model.ModuleNameV2
import com.navi.common.ui.errorview.FullScreenErrorComposeView
import com.navi.common.utils.setStatusBarColorInt
import com.navi.design.utils.parseColorSafe
@@ -24,6 +25,7 @@ import com.naviapp.home.dashboard.ui.compose.investmentTab.InvestmentsTabShimmer
import com.naviapp.home.dashboard.viewmodels.InvestmentsVm
import com.naviapp.home.utils.InvestmentTabEvents
import com.naviapp.home.viewmodel.SharedVM
import com.naviapp.utils.Constants.INVESTMENT_TAB_SCREEN_V3
@Composable
fun InvestmentsScreen(
@@ -70,6 +72,10 @@ fun InvestmentsScreen(
investmentsScreenHelper = investmentsScreenHelper,
bottomNavBarVM = bottomNavBarVM
)
investmentsTabVm.recordScreenRenderTime(
INVESTMENT_TAB_SCREEN_V3,
ModuleNameV2.AMC.name
)
}
}
is InvestmentsVm.InvestmentsTabScreenState.Error -> {
@@ -77,6 +83,10 @@ fun InvestmentsScreen(
error = investmentsScreenData.error,
onRetryClick = { investmentsTabVm.fetchInvestmentTabScreen() }
)
investmentsTabVm.recordScreenRenderTime(
INVESTMENT_TAB_SCREEN_V3,
ModuleNameV2.AMC.name
)
}
}
}

View File

@@ -115,6 +115,10 @@ constructor(
val bottomStickyNudgeData: StateFlow<InvestmentTabNudgeData?>
get() = _bottomStickyNudgeData
init {
recordScreenLandTime(INVESTMENT_TAB_SCREEN_V3)
}
fun setTimerChangeData(data: String?) {
_cutOffTimerDataChange.value = data
}
@@ -212,6 +216,7 @@ constructor(
val response =
investmentsTabRepository.fetchInvestmentTabScreenResponse(screenName, metricInfo)
if (response.isValidResponse()) {
recordApiEndTime(INVESTMENT_TAB_SCREEN_V3)
response.data?.let { data ->
_statusBarColor.emit(data.metaData?.get(STATUS_BAR_COLOR) ?: YELLOW_COLOR)
data.bottomStickyNudgeData?.let {

View File

@@ -32,6 +32,7 @@ import com.navi.base.utils.orTrue
import com.navi.base.utils.orZero
import com.navi.common.listeners.FragmentInterchangeListener
import com.navi.common.listeners.HeaderInteractionListener
import com.navi.common.model.ModuleNameV2
import com.navi.common.model.UploadDataAsyncResponse
import com.navi.common.ui.fragment.SingleSelectionBottomSheet
import com.navi.common.utils.ApiPollScheduler
@@ -74,12 +75,14 @@ class EmploymentDetailsFragment : AmcBaseFragment(), WidgetCallback, FooterInter
private fun fetchData() {
showLoader()
recordApiStartTime(screenName)
viewModel.fetchData()
viewModel.fetchTracker()
}
private fun initObservers() {
viewModel.dataItems.observe(viewLifecycleOwner) { response ->
recordApiEndTime(screenName)
hideLoader()
setHeaderProperties(response?.header)
hideDivider()
@@ -90,6 +93,7 @@ class EmploymentDetailsFragment : AmcBaseFragment(), WidgetCallback, FooterInter
adapter = FormAdapter(response?.content?.widgets.orEmpty(), this)
binding.recycleView.layoutManager = LinearLayoutManager(requireContext())
binding.recycleView.adapter = adapter
recordScreenRenderTime(screenName, ModuleNameV2.AMC.name)
}
viewModel.postDataResponse.observe(viewLifecycleOwner) { response ->
response?.requestId?.let { apiPollInit(response) }

View File

@@ -59,6 +59,7 @@ import com.navi.base.utils.orFalse
import com.navi.common.CommonLibManager
import com.navi.common.listeners.FragmentInterchangeListener
import com.navi.common.listeners.HeaderInteractionListener
import com.navi.common.model.ModuleNameV2
import com.navi.common.model.UploadDataAsyncResponse
import com.navi.common.network.models.GenericErrorResponse
import com.navi.common.utils.ApiPollScheduler
@@ -101,11 +102,13 @@ class KycStartFragment : AmcBaseFragment(), OKYCListener {
private fun fetchData() {
showLoader()
recordApiStartTime(screenName)
viewModel.fetchData()
}
private fun initObservers() {
viewModel.dataItems.observe(viewLifecycleOwner) { response ->
recordApiEndTime(screenName)
hideLoader()
response?.content?.optionsPageContent?.let { optionsContent ->
val bundle =
@@ -148,7 +151,7 @@ class KycStartFragment : AmcBaseFragment(), OKYCListener {
arguments?.getParcelable<GenericErrorResponse>(CheckerActivity.ERROR_DATA)?.let {
viewModel.setErrorData(listOf(it))
}
recordScreenRenderTime(screenName, ModuleNameV2.AMC.name)
sendInitEvent()
}
viewModel.kycDigioConfig.observe(viewLifecycleOwner) { response ->

View File

@@ -37,6 +37,7 @@ import com.navi.base.utils.isNotNullAndNotEmpty
import com.navi.base.utils.orTrue
import com.navi.common.listeners.FragmentInterchangeListener
import com.navi.common.listeners.HeaderInteractionListener
import com.navi.common.model.ModuleNameV2
import com.navi.common.network.models.GenericErrorResponse
import com.navi.design.utils.*
import com.navi.naviwidgets.adapters.FormAdapter
@@ -85,6 +86,7 @@ class PanFragment : AmcBaseFragment(), WidgetCallback, FooterInteractionListener
private fun fetchData() {
showLoader()
recordApiStartTime(screenName)
when (pageType) {
SubPageStatusType.PAN -> viewModel.fetchData()
SubPageStatusType.NAME,
@@ -95,7 +97,11 @@ class PanFragment : AmcBaseFragment(), WidgetCallback, FooterInteractionListener
}
private fun initObservers() {
viewModel.panItems.observe(viewLifecycleOwner) { response -> renderUI(response) }
viewModel.panItems.observe(viewLifecycleOwner) { response ->
recordApiEndTime(screenName)
renderUI(response)
recordScreenRenderTime(screenName, ModuleNameV2.AMC.name)
}
viewModel.postData.observe(viewLifecycleOwner) {
hideLoader()
fragmentInterchangeListener?.navigateToNextScreen(

View File

@@ -46,6 +46,7 @@ import com.navi.base.utils.orFalse
import com.navi.base.utils.orTrue
import com.navi.common.listeners.FragmentInterchangeListener
import com.navi.common.listeners.HeaderInteractionListener
import com.navi.common.model.ModuleNameV2
import com.navi.common.model.UploadDataAsyncResponse
import com.navi.common.pushnotification.NotificationConstants
import com.navi.common.utils.ApiPollScheduler
@@ -89,11 +90,13 @@ class PersonalDetailsFragment :
private fun fetchData() {
showLoader()
recordApiStartTime(screenName)
viewModel.fetchData()
}
private fun initObservers() {
viewModel.dataItems.observe(viewLifecycleOwner) { response ->
recordApiEndTime(screenName)
hideLoader()
setHeaderProperties(response?.header)
hideDivider()
@@ -115,6 +118,7 @@ class PersonalDetailsFragment :
view?.let { (it as LabeledTextInputWidgetV2).setListener { populateEmail() } }
}
}
recordScreenRenderTime(screenName, ModuleNameV2.AMC.name)
}
viewModel.postDataResponse.observe(viewLifecycleOwner) { response ->
response?.requestId?.let { apiPollInit(response) }

View File

@@ -150,8 +150,12 @@ constructor(
stringResouceProvider.getString(R.string.bbps_new_contact)
init {
recordScreenLandTime(screen = naviBbpsVmData.screen.screenName)
viewModelScope.launch(dispatcherProvider.io) {
launch { fetchBillHistoryList() }
launch {
recordApiStartTime(screen = naviBbpsVmData.screen.screenName)
fetchBillHistoryList()
}
launch {
naviBbpsDefaultConfig =
naviBbpsConfigUseCase.getDefaultConfig(naviBbpsVmData.screen.screenName)
@@ -204,7 +208,6 @@ constructor(
savedBillId = myBillEntity.billId,
metricInfo = getBbpsMetricInfo(screenName = naviBbpsVmData.screen.screenName)
)
if (billTransactionsResponse.isSuccessWithData()) {
val transactions = billTransactionsResponse.data!!.transactions.orEmpty()
_billHistoryDetailsState.update {

View File

@@ -40,11 +40,14 @@ import com.navi.naviwidgets.extensions.NaviText
@Composable
fun BillTransactionsListView(
billHistoryDetailsState: BillTransactionsState,
onItemClicked: (BillTransactionItemEntity) -> Unit
onItemClicked: (BillTransactionItemEntity) -> Unit,
recordScreenRenderTime: () -> Unit,
recordApiEndTime: () -> Unit
) {
when (billHistoryDetailsState) {
is BillTransactionsState.Loading -> MyBillsTransactionsShimmer()
is BillTransactionsState.Loaded -> {
recordApiEndTime()
NaviText(
modifier = Modifier.padding(horizontal = NaviBbpsDimens.horizontalMargin),
text = stringResource(id = R.string.bbps_bill_payment_history),
@@ -66,6 +69,7 @@ fun BillTransactionsListView(
}
}
}
recordScreenRenderTime()
}
is BillTransactionsState.Empty -> {}
is BillTransactionsState.Error -> {}

View File

@@ -56,6 +56,7 @@ import com.navi.bbps.feature.billhistorydetail.model.view.BillTransactionItemEnt
import com.navi.bbps.feature.mybills.model.view.MyBillEntity
import com.navi.common.R as CommonR
import com.navi.common.customview.LoaderRoundedButton
import com.navi.common.model.ModuleNameV2
import com.navi.design.font.FontWeightEnum
import com.navi.design.font.getFontWeight
import com.navi.design.font.naviFontFamily
@@ -243,7 +244,18 @@ fun MyBillHistoryDetailsScreen(
)
BillTransactionsListView(
billHistoryDetailsState = billHistoryDetailsState,
onItemClicked = onTransactionItemClicked
onItemClicked = onTransactionItemClicked,
recordScreenRenderTime = {
billHistoryDetailsViewModel.recordScreenRenderTime(
billHistoryDetailsViewModel.naviBbpsVmData.screen.screenName,
ModuleNameV2.BBPS.name
)
},
recordApiEndTime = {
billHistoryDetailsViewModel.recordApiEndTime(
billHistoryDetailsViewModel.naviBbpsVmData.screen.screenName,
)
}
)
}
},

View File

@@ -104,6 +104,7 @@ constructor(
private var naviBbpsDefaultConfig = NaviBbpsDefaultConfig()
init {
recordScreenLandTime(screen = naviBbpsVmData.screen.screenName)
initConfig()
fetchMySavedBills()
}
@@ -136,7 +137,7 @@ constructor(
val isBillReminderEnabled = isBillReminderEnabled()
naviBbpsAnalytics.onVmInit(isBillReminderEnabled = isBillReminderEnabled)
recordApiStartTime(screen = naviBbpsVmData.screen.screenName)
myBillsRepository.fetchMySavedBills().collect { myBillEntities ->
val myUnpaidBills =
if (isBillReminderEnabled) myBillEntities.filter { it.isBillPaid.not() }

View File

@@ -38,6 +38,7 @@ import com.navi.bbps.feature.destinations.MyBillHistoryDetailsScreenDestination
import com.navi.bbps.feature.mybills.MyBillsViewModel
import com.navi.bbps.feature.mybills.model.view.MyBillEntity
import com.navi.bbps.feature.mybills.model.view.MyBillsState
import com.navi.common.model.ModuleNameV2
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.result.NavResult
@@ -174,7 +175,10 @@ fun MyBillsScreen(
) {
when (myBillsState) {
MyBillsState.Loading -> MyBillsShimmer()
is MyBillsState.Loaded ->
is MyBillsState.Loaded -> {
myBillsViewModel.recordApiEndTime(
myBillsViewModel.naviBbpsVmData.screen.screenName
)
RenderMyBillsScreen(
isBillReminderEnabled =
(myBillsState as MyBillsState.Loaded).isBillReminderEnabled,
@@ -197,6 +201,11 @@ fun MyBillsScreen(
},
onBillMarkAsPaidClicked = onBillMarkAsPaidClicked,
)
myBillsViewModel.recordScreenRenderTime(
myBillsViewModel.naviBbpsVmData.screen.screenName,
ModuleNameV2.BBPS.name
)
}
is MyBillsState.Empty -> {
RenderEmptyMyBillsScreen(
naviBbpsAnalytics = naviBbpsAnalytics,

View File

@@ -7,29 +7,71 @@
package com.navi.common.checkmate.core
import com.navi.common.checkmate.model.MetricInfo
import com.navi.base.utils.orZero
interface CheckMateMapper {
fun recordScreenLandTime(screen: String)
fun <T> recordScreenRenderLatency(metricInfo: MetricInfo<T>)
fun recordApiStartTime(screen: String)
fun recordApiEndTime(screen: String, source: DataSource = DataSource.Backend)
fun recordScreenRenderTime(screen: String, vertical: String)
}
object CheckMateLatencyMapper : CheckMateMapper {
private val latencyMap: MutableMap<String, Long> = mutableMapOf()
private val screenLandTimeMap: MutableMap<String, Long> = mutableMapOf()
private val apiStartTimeMap: MutableMap<String, Long> = mutableMapOf()
private val apiEndTimeMap: MutableMap<String, Long> = mutableMapOf()
private val dataSource: MutableMap<String, String> = mutableMapOf()
override fun recordScreenLandTime(screen: String) {
latencyMap[screen] = System.currentTimeMillis()
screenLandTimeMap[screen] = System.currentTimeMillis()
}
override fun <T> recordScreenRenderLatency(metricInfo: MetricInfo<T>) {
val screenStartTime = latencyMap[metricInfo.screen]
if (screenStartTime != null) {
latencyMap.remove(metricInfo.screen)
CheckMateManager.logScreenLatencyEvent(
metricInfo = metricInfo,
latency = System.currentTimeMillis() - screenStartTime
)
override fun recordApiStartTime(screen: String) {
if (screenLandTimeMap[screen] != null && apiStartTimeMap[screen] == null) {
apiStartTimeMap[screen] = System.currentTimeMillis()
}
}
override fun recordApiEndTime(screen: String, source: DataSource) {
if (apiStartTimeMap[screen] != null && apiEndTimeMap[screen] == null) {
apiEndTimeMap[screen] = System.currentTimeMillis()
dataSource[screen] = source.name
}
}
override fun recordScreenRenderTime(screen: String, vertical: String) {
if (
screenLandTimeMap[screen] == null ||
apiStartTimeMap[screen] == null ||
apiEndTimeMap[screen] == null
)
return
val screenLandTime = screenLandTimeMap[screen].orZero()
val apiStartTime = apiStartTimeMap[screen].orZero()
val apiEndTime = apiEndTimeMap[screen].orZero()
val source = dataSource[screen].orEmpty()
screenLandTimeMap.remove(screen)
apiStartTimeMap.remove(screen)
apiEndTimeMap.remove(screen)
CheckMateManager.logScreenLatencyEvent(
screen = screen,
vertical = vertical,
source = source,
apiStartDelayTime = apiStartTime - screenLandTime,
apiE2ELatency = apiEndTime - apiStartTime,
uIRenderLatency = System.currentTimeMillis() - apiEndTime,
screenE2ELatency = System.currentTimeMillis() - screenLandTime
)
}
}
enum class DataSource {
Backend,
DB,
Memory
}

View File

@@ -131,15 +131,26 @@ object CheckMateManager {
)
}
fun <T> logScreenLatencyEvent(metricInfo: MetricInfo<T>, latency: Long) {
fun logScreenLatencyEvent(
screen: String,
vertical: String,
source: String,
apiStartDelayTime: Long,
apiE2ELatency: Long,
uIRenderLatency: Long,
screenE2ELatency: Long
) {
NaviTrackEvent.trackEventOnClickStream(
eventName =
getEventNameWithVerticalPrefix("screen_latency_metric", metricInfo.vertical),
eventName = getEventNameWithVerticalPrefix("screen_latency_metric", vertical),
eventValues =
mapOf(
"vertical" to metricInfo.vertical,
"screen" to metricInfo.screen,
"latency" to latency.toString(),
"vertical" to vertical,
"screen" to screen,
"source" to source,
"apiStartDelayTime" to apiStartDelayTime.toString(),
"apiE2ELatency" to apiE2ELatency.toString(),
"uIRenderLatency" to uIRenderLatency.toString(),
"screenE2ELatency" to screenE2ELatency.toString(),
"alfredSessionId" to AlfredManager.getAlfredSessionId()
)
)

View File

@@ -24,12 +24,14 @@ import com.navi.base.utils.isNotNull
import com.navi.base.utils.isNotNullAndNotEmpty
import com.navi.base.utils.orFalse
import com.navi.common.R as CommonR
import com.navi.common.checkmate.core.DataSource
import com.navi.common.di.CoroutineDispatcherProvider
import com.navi.common.firebaseremoteconfig.FirebaseRemoteConfigHelper
import com.navi.common.firebaseremoteconfig.FirebaseRemoteConfigHelper.NAVI_PAY_REMOVE_APP_ON_INTENT_PAYMENT_SUCCESS
import com.navi.common.firebaseremoteconfig.FirebaseRemoteConfigHelper.NAVI_PAY_REMOVE_TASK_ON_INTENT_PAYMENT_SUCCESS
import com.navi.common.firebaseremoteconfig.FirebaseRemoteConfigHelper.NAVI_PAY_SCRATCH_CARD_OPTIMISATION_V2_ENABLED
import com.navi.common.firebaseremoteconfig.FirebaseRemoteConfigHelper.NAVI_PAY_UPI_LITE_LOW_BALANCE_NOTIFICATION_PN_DISABLED
import com.navi.common.model.ModuleNameV2
import com.navi.common.network.models.RepoResult
import com.navi.common.network.models.isSuccess
import com.navi.common.network.models.isSuccessWithData
@@ -522,6 +524,7 @@ constructor(
private val isLiteAutoTopUpExperimentEnabled = MutableStateFlow(false)
init {
recordScreenLandTime(screenName)
setLitmusExperimentValues()
updateNaviPayDefaultConfig()
updateUPILiteConfig()
@@ -1867,8 +1870,9 @@ constructor(
isPayeeVerified = payeeEntity.value.isVerifiedVpa,
naviPaySessionAttributes = getNaviPaySessionAttributes()
)
recordApiStartTime(screenName)
if (payeeEntity.value.isVerifiedVpa) {
recordApiEndTime(screenName, DataSource.Memory)
onVpaValidationSuccess()
return true
}
@@ -1895,7 +1899,7 @@ constructor(
transactionType = transactionType,
naviPaySessionAttributes = getNaviPaySessionAttributes()
)
recordApiEndTime(screenName)
if (validateVpaAPIResponse.isSuccessWithData()) {
updatePayeeEntity(
payeeEntity =
@@ -1915,6 +1919,7 @@ constructor(
isNpciData = validateVpaAPIResponse.data!!.isNpciData
)
)
recordScreenRenderTime(screenName, ModuleNameV2.NAVIPAY.name)
onVpaValidationSuccess()
return true
} else {
@@ -1947,7 +1952,7 @@ constructor(
} else {
notifyError(response = validateVpaAPIResponse, cancelable = false, tag = errorTag)
}
recordScreenRenderTime(screenName, ModuleNameV2.NAVIPAY.name)
triggerKeyboardVisibility(visibility = false)
return false
}

View File

@@ -22,6 +22,7 @@ import com.navi.base.utils.orTrue
import com.navi.base.utils.orZero
import com.navi.common.checkmate.core.CheckMateManager
import com.navi.common.checkmate.model.MetricInfo
import com.navi.common.model.ModuleNameV2
import com.navi.common.network.models.isSuccessWithData
import com.navi.common.upi.UpiDataType
import com.navi.common.utils.toJsonObject
@@ -190,6 +191,7 @@ constructor(
init {
recordScreenLandTime(screenName)
recordApiStartTime(screenName)
initSdkInitParams()
getPaymentMethodData()
viewModelScope.launch(Dispatchers.IO) { getNaviUpiConnectedAccounts() }
@@ -217,6 +219,7 @@ constructor(
paymentDataProvider.getAndRemove(PaymentDataProvider.ERROR_RESPONSE)
as PaymentErrorData?
errorData?.let {
recordApiEndTime(screenName)
updateBottomSheetUIState(
showBottomSheet = true,
bottomSheetUIState =
@@ -229,7 +232,7 @@ constructor(
),
bottomSheetStateChange = true
)
recordScreenRenderTime(screenName, ModuleNameV2.PG.name)
delay(500)
isDismissAllowed = true
}
@@ -242,7 +245,9 @@ constructor(
paymentDataProvider.get(PaymentDataProvider.ACTION_TYPE) ==
PaymentMethodType.S2S_INTEGRATION.name
) {
recordApiEndTime(screenName)
refreshUI(data)
recordScreenRenderTime(screenName, ModuleNameV2.PG.name)
} else {
_npsRedirection.update { true }
}

View File

@@ -8,7 +8,6 @@
package com.navi.payment.nativepayment.viewmodel
import androidx.lifecycle.viewModelScope
import com.navi.common.checkmate.model.MetricInfo
import com.navi.common.model.ModuleNameV2
import com.navi.common.network.models.ErrorMessage
import com.navi.common.network.models.GenericErrorResponse
@@ -115,7 +114,7 @@ abstract class NaviPaymentBaseVM(open val screenName: String) : BaseVM() {
}
fun recordScreenLatency(screenName: String) {
recordScreenRenderLatency(metricInfo = MetricInfo.PMSMetric<Boolean>(screen = screenName))
recordScreenRenderTime(screenName, ModuleNameV2.PG.name)
}
companion object {