NTP-4562 || Missing events in AMC Onboarding journey & Source screen name in event attributes || unused code cleanup (#12972)

Co-authored-by: Aman <amankasyapp@gmail.com>
This commit is contained in:
Aman S
2024-10-09 16:36:56 +05:30
committed by GitHub
parent 4ea06a6ee4
commit 856997c236
12 changed files with 78 additions and 237 deletions

View File

@@ -11,6 +11,8 @@ import android.os.Bundle
import android.os.Parcelable
import com.navi.amc.common.fragment.HelpBottomSheet
import com.navi.amc.utils.AmcAnalytics
import com.navi.amc.utils.AmcAnalytics.ACTIVITY_LAND
import com.navi.amc.utils.TempStorageHelper
import com.navi.amc.utils.toNavigateAmcModule
import com.navi.base.deeplink.DeepLinkManager
import com.navi.base.deeplink.util.DeeplinkConstants
@@ -40,6 +42,21 @@ abstract class AmcBaseActivity : BaseActivity() {
backPress()
}
override fun onResume() {
super.onResume()
TempStorageHelper.updateScreenNames(screenName)
sendLandEvent()
}
private fun sendLandEvent() {
sendEvent(screenName + ACTIVITY_LAND)
}
override fun onStop() {
super.onStop()
TempStorageHelper.setPreviousScreenName(screenName)
}
protected fun backPress() {
if (isTaskRoot) {
DeepLinkManager.getDeepLinkListener()

View File

@@ -13,12 +13,13 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.ViewStub
import androidx.core.view.isVisible
import androidx.fragment.app.activityViewModels
import com.navi.amc.common.taskProcessor.AmcTaskManager
import com.navi.amc.databinding.AmcBaseFragmentLayoutBinding
import com.navi.amc.fundbuy.viewmodel.FundBuyFlowViewModel
import com.navi.amc.utils.AmcAnalytics
import com.navi.amc.utils.AmcAnalytics.LAND
import com.navi.amc.utils.TempStorageHelper
import com.navi.base.model.GenericAnalyticsData
import com.navi.common.listeners.HeaderInteractionListener
import com.navi.common.model.Header
@@ -101,10 +102,16 @@ abstract class AmcBaseFragment : BaseFragment() {
override fun onResume() {
super.onResume()
TempStorageHelper.updateScreenNames(screenName)
sendLandEvent()
screenEnterTimeStamp = System.currentTimeMillis()
launchCounter++
}
private fun sendLandEvent() {
sendEvent(screenName + LAND)
}
override fun onPause() {
super.onPause()
sendEvent(
@@ -118,6 +125,11 @@ abstract class AmcBaseFragment : BaseFragment() {
)
}
override fun onStop() {
super.onStop()
TempStorageHelper.setPreviousScreenName(screenName)
}
protected open fun popThisFromBackStack() {
try {
buyFlowVM.removeLastScreen()

View File

@@ -1,17 +0,0 @@
/*
*
* * Copyright © 2019-2024 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
package com.navi.amc.databinding
import android.graphics.drawable.Drawable
import android.widget.TextView
import androidx.databinding.BindingAdapter
@BindingAdapter("bind:setDrawableEnd")
fun setDrawableEnd(textView: TextView, resId: Drawable) {
textView.setCompoundDrawablesWithIntrinsicBounds(null, null, resId, null)
}

View File

@@ -27,8 +27,8 @@ import com.navi.amc.fundbuy.viewmodel.AutoPaySetupScreenViewModel
import com.navi.amc.utils.AmcAnalytics
import com.navi.amc.utils.AmcAnalytics.AMC_AUTOPAY_MODE_CHANGED
import com.navi.amc.utils.AmcAnalytics.AMC_AUTOPAY_MODE_CLICKED
import com.navi.amc.utils.AmcAnalytics.AMC_INIT_AUTOPAY_SETUP_SCREEN
import com.navi.amc.utils.AmcAnalytics.LIMIT
import com.navi.amc.utils.AmcAnalytics.SIP_AUTO_PAY_LAND
import com.navi.amc.utils.Constant
import com.navi.amc.utils.Constant.AMOUNT
import com.navi.amc.utils.Constant.DISMISS
@@ -60,7 +60,7 @@ class AutoPaySetupFragmentV2 : AmcBaseFragment() {
private val paymentSharedVM: PaymentSharedVM by activityViewModels()
private lateinit var binding: AutoPaySetupLayoutBinding
override val screenName: String
get() = AmcAnalytics.SIP_TYPE
get() = SIP_AUTO_PAY_LAND
override fun onAttach(context: Context) {
super.onAttach(context)
@@ -212,10 +212,7 @@ class AutoPaySetupFragmentV2 : AmcBaseFragment() {
true
} ?: run { false }
}
sendEvent(
AMC_INIT_AUTOPAY_SETUP_SCREEN,
hashMapOf(LIMIT to viewModel.getAutoPayLimit())
)
sendEvent(SIP_AUTO_PAY_LAND, hashMapOf(LIMIT to viewModel.getAutoPayLimit()))
}
}

View File

@@ -31,7 +31,7 @@ import com.navi.amc.fundbuy.viewmodel.SipTypeViewModel
import com.navi.amc.utils.AmcAnalytics.AMC_SIP_CHOOSE_TYPE_CLICKED
import com.navi.amc.utils.AmcAnalytics.ISIN
import com.navi.amc.utils.AmcAnalytics.SELECTED_TYPE
import com.navi.amc.utils.AmcAnalytics.SIP_TYPE
import com.navi.amc.utils.AmcAnalytics.SIP_CHOOSE_TYPE_LAND
import com.navi.amc.utils.Constant
import com.navi.amc.utils.Constant.AMOUNT
import com.navi.amc.utils.Constant.CONTINUE
@@ -59,7 +59,7 @@ class SipTypeFragment() : AmcBaseFragment() {
private val viewModel by viewModels<SipTypeViewModel>()
private lateinit var binding: SipTypeLayoutBinding
override val screenName: String
get() = SIP_TYPE
get() = SIP_CHOOSE_TYPE_LAND
override fun onAttach(context: Context) {
super.onAttach(context)

View File

@@ -43,7 +43,7 @@ import com.navi.amc.network.util.ApiConstants
import com.navi.amc.utils.AmcAnalytics
import com.navi.amc.utils.AmcAnalytics.AMC_BTN_KYC_DIGILOCKER_ONBRD_CONTINUE
import com.navi.amc.utils.AmcAnalytics.AMC_BTN_KYC_OKYC_ONBRD_CONTINUE
import com.navi.amc.utils.AmcAnalytics.AMC_INIT_KYC_OKYC_SUCCESS
import com.navi.amc.utils.AmcAnalytics.AMC_INIT_KYC_OKYC_SDK_EXIT
import com.navi.amc.utils.AmcAnalytics.AMC_LATENCY_KYC_INITIATION_TIME
import com.navi.amc.utils.Constant
import com.navi.amc.utils.Constant.DATA
@@ -379,6 +379,14 @@ class KycStartFragment : AmcBaseFragment(), OKYCListener {
details = AadhaarDetails(txnId = data?.optString(Constant.TXN_ID))
)
)
sendEvent(
AMC_INIT_KYC_OKYC_SDK_EXIT,
extraAttributes =
hashMapOf(
"statusCode" to error.errorCode.toString(),
"errorMessage" to error.errorMessage.toString()
)
)
}
?: run {
showLoader()
@@ -390,7 +398,14 @@ class KycStartFragment : AmcBaseFragment(), OKYCListener {
details = AadhaarDetails(txnId = data?.optString("txnId"))
)
)
sendEvent(AMC_INIT_KYC_OKYC_SUCCESS)
sendEvent(
AMC_INIT_KYC_OKYC_SDK_EXIT,
extraAttributes =
hashMapOf(
"statusCode" to ApiConstants.API_SUCCESS_CODE.toString(),
"message" to FirebaseStatusType.SUCCESS
)
)
}
}
}

View File

@@ -12,6 +12,7 @@ import com.navi.analytics.utils.NaviTrackEvent
import com.navi.base.model.GenericAnalyticsData
import com.navi.base.utils.BaseUtils
import com.navi.base.utils.orElse
import com.navi.common.upi.SOURCE_SCREEN_NAME
@Keep
object AmcAnalytics {
@@ -57,6 +58,7 @@ object AmcAnalytics {
const val INVESTMENT_DETAILS = "investment_details"
const val OTP_REDEEM_INIT = "amc_init_redeem_otp"
const val OTP_INIT = "amc_init_otp_screen"
const val AMOUNT_PAGE_LAND = "amc_amount_page_land"
const val PORTFOLIO = "amc_init_investments_portfolio"
const val AUTOPAY_MODIFY = "amc_init_autopay_mandate"
const val AUTOPAY_SUCCESS = "amc_init_autopay_success"
@@ -118,6 +120,7 @@ object AmcAnalytics {
const val AMC_INIT_KYC_AADHAAR_ESIGN_CONTINUE = "amc_init_kyc_aadhaar_esign_continue"
const val AMC_BTN_KYC_OKYC_ONBRD_CONTINUE = "amc_btn_kyc_okyc_onbrd_continue"
const val AMC_INIT_KYC_OKYC_SUCCESS = "amc_init_kyc_okyc_success"
const val AMC_INIT_KYC_OKYC_SDK_EXIT = "amc_init_kyc_okyc_sdk_exit"
const val AMC_BTN_INVEST_SETUP_CREATE_LUMPSUM = "amc_btn_invest_setup_create_lumpsum"
const val AMC_BTN_INVEST_SETUP_CREATE_SIP = "amc_btn_invest_setup_create_sip"
@@ -181,7 +184,8 @@ object AmcAnalytics {
const val AMOUNT_REDEEMED = "amount_redeemed"
const val UNITS_REDEEMED = "units_redeemed"
const val PERC_TOTAL_FUND_VALUE = "perc_total_fund_value"
const val SIP_TYPE = "sip_type"
const val SIP_AUTO_PAY_LAND = "amc_sip_auto_pay_page_land"
const val SIP_CHOOSE_TYPE_LAND = "amc_sip_choose_type_page_land"
const val AMC_INIT_SIMPLIFIED_LUMPSUM = "amc_init_simplified_lumpsum"
const val AMC_INIT_SIMPLIFIED_SIP = "amc_init_simplified_sip"
@@ -198,6 +202,8 @@ object AmcAnalytics {
const val LATENCY_END_TIME = "end_time"
const val LATENCY_STATUS = "status"
const val SCREEN_NAME = "screen_name"
const val LAND = "_land"
const val ACTIVITY_LAND = "activity_land"
const val AMC_LATENCY_KYC_INITIATION_TIME = "amc_latency_kyc_initiation_time"
const val AMC_LATENCY_KYC_PROCESSING_TIME = "amc_latency_kyc_processing_time"
const val AMC_LATENCY_KYC_CALLBACK_TIME = "amc_latency_kyc_callback_time"
@@ -305,6 +311,8 @@ object AmcAnalytics {
val attributes = HashMap<String, String>()
eventsData?.parameters?.let { attributes.putAll(it) }
extraAttributes?.let { attributes.putAll(it) }
attributes[SOURCE_SCREEN_NAME] = TempStorageHelper.getPreviousScreenName().toString()
attributes[SCREEN_NAME] = screenName
sendEvent(
eventsData?.eventName.orElse(AMC_EMPTY_EVENT_ + screenName),
attributes,
@@ -320,6 +328,8 @@ object AmcAnalytics {
) {
val attributes = HashMap<String, String>()
extraAttributes?.let { attributes.putAll(it) }
attributes[SOURCE_SCREEN_NAME] = TempStorageHelper.getPreviousScreenName().toString()
attributes[SCREEN_NAME] = screenName
sendEvent(
eventName.orElse(AMC_EMPTY_EVENT_ + screenName),
attributes,

View File

@@ -64,13 +64,6 @@ object ColorUtils {
gradientOrientation = orientation
)
fun getRedBorderRoundedDrawable(context: Context?) =
getNaviDrawable(
strokeColor = context?.let { ContextCompat.getColor(it, DesignR.color.linkColor) },
cornerRadius = dpToPx(12).toInt(),
strokeWidth = dpToPx(1).toInt()
)
fun getPurpleBorderRoundedDrawable(context: Context?) =
getNaviDrawable(
strokeColor = context?.let { ContextCompat.getColor(it, DesignR.color.color_1F002A) },
@@ -94,31 +87,10 @@ object ColorUtils {
backgroundColor = ContextCompat.getColor(context, com.navi.amc.R.color.white)
)
fun getDarkGreyBorder8StrokeDrawable(context: Context) =
getNaviDrawable(
cornerRadius = dpToPxInInt(8),
strokeColor = ContextCompat.getColor(context, R.color.color_dark_gray),
strokeWidth = dpToPxInInt(1)
)
fun getBorder8StrokeDrawable(color: Int) =
getNaviDrawable(
cornerRadius = dpToPxInInt(8),
strokeColor = color,
strokeWidth = dpToPxInInt(1)
)
fun getBorder4StrokeDrawable(color: Int) =
getNaviDrawable(
cornerRadius = dpToPxInInt(4),
strokeColor = color,
strokeWidth = dpToPxInInt(1)
)
fun getGreenBorder8StrokeDrawable(context: Context) =
getNaviDrawable(
cornerRadius = dpToPxInInt(8),
strokeColor = ContextCompat.getColor(context, R.color.dark_green),
strokeWidth = dpToPxInInt(1)
)
}

View File

@@ -7,61 +7,8 @@
package com.navi.amc.utils
import java.text.SimpleDateFormat
import java.util.*
class DateUtils {
fun getYesterdayDate(): String {
val now: Calendar = Calendar.getInstance()
now.add(Calendar.DATE, -1)
val dateFormat: SimpleDateFormat = SimpleDateFormat("MMM dd,yyyy")
return dateFormat.format(now.time)
}
fun getLastMonth(): String {
val now: Calendar = Calendar.getInstance()
now.add(Calendar.MONTH, -1)
val dateFormat: SimpleDateFormat = SimpleDateFormat("MMM")
return dateFormat.format(now.time)
}
fun getLastMonthDate(): String {
val now: Calendar = Calendar.getInstance()
now.add(Calendar.MONTH, -1)
val dateFormat: SimpleDateFormat = SimpleDateFormat("MMM-dd-yyyy")
return dateFormat.format(now.time)
}
fun getLastDayofMonth(): Int {
val date = getLastMonthDate()
val dateFormat1 = SimpleDateFormat("MMM-dd-yyyy")
val convertedDate = dateFormat1.parse(date)
val c = Calendar.getInstance()
c.time = convertedDate
c[Calendar.DAY_OF_MONTH] = c.getActualMaximum(Calendar.DAY_OF_MONTH)
val dateFormat: SimpleDateFormat = SimpleDateFormat("dd")
return Integer.parseInt(dateFormat.format(c.time))
}
fun getFormattedDate(date: String): String {
val dateFormat1 = SimpleDateFormat("dd-MM-yyyy HH:mm:ss")
val convertedDate = dateFormat1.parse(date)
val dateFormat: SimpleDateFormat = SimpleDateFormat("dd-MMM-yyyy")
return dateFormat.format(convertedDate)
}
fun formatSecondsInDaysTimer(timeInSeconds: Long): String {
val secondsLeft = timeInSeconds % 3600 % 60
val minutes = timeInSeconds % 3600 / 60

View File

@@ -28,7 +28,6 @@ import com.navi.amc.common.fragment.*
import com.navi.amc.fundbuy.fragments.*
import com.navi.amc.fundbuy.models.AmcWebLandingPageResponse
import com.navi.amc.fundbuy.models.FundExtraData
import com.navi.amc.fundbuy.models.FundListResponse
import com.navi.amc.fundbuy.models.LabelData
import com.navi.amc.fundbuy.models.Option
import com.navi.amc.fundbuy.models.Temperature
@@ -62,7 +61,6 @@ import com.navi.design.utils.setSpannableString
import com.navi.naviwidgets.utils.CUSTOM_TIME_FORMAT
import java.math.RoundingMode
import java.text.DecimalFormat
import java.text.NumberFormat
import java.text.SimpleDateFormat
import java.util.*
import java.util.concurrent.TimeUnit
@@ -71,18 +69,6 @@ fun Int?.orValue(value: Int) = this ?: value
fun Long?.orValue(value: Long) = this ?: value
fun String.addComma(): String {
return try {
val originalString = this.removeComma()
val longval = originalString.toDouble()
val formatter: DecimalFormat = NumberFormat.getInstance(Locale.US) as DecimalFormat
formatter.applyPattern("##,##,##,##,##,##,##,##,##,###.##")
formatter.format(longval)
} catch (nfe: NumberFormatException) {
""
}
}
fun String.removeComma(): String {
return try {
this.replace(",", "")
@@ -121,10 +107,6 @@ fun getPaymentSyncFlowStatusCta(type: String): String {
return amcDeeplink(NaviAmcDeeplinkNavigator.CHECKER.plus("/").plus(type))
}
fun String.isNegativeNumber(): Boolean {
return this.contains("-")
}
fun ActionData.toNavigateAmcModule(
activity: Activity?,
finish: Boolean? = false,
@@ -257,10 +239,6 @@ fun getFragment(screen: String, bundle: Bundle): Fragment? {
}
}
fun isNeedToAddInBackStack(screen: String): Boolean {
return screen != SubPageStatusType.STATUS
}
fun getBottomSheet(
screen: String,
bundle: Bundle,
@@ -332,33 +310,6 @@ fun dateFormat(date: Date): String {
return sdf.format(date)
}
fun String.parseDate(format: String) = SimpleDateFormat(format).parse(this)
fun Date.formatAs(format: String) = SimpleDateFormat(format).format(this)
fun String.changeDateFormat(inputFormat: String, outputFormat: String) =
SimpleDateFormat(inputFormat).parse(this).formatAs(outputFormat)
fun Date.prettifyDate(): String {
val suffix =
Calendar.getInstance().let {
it.time = this
it.get(Calendar.DAY_OF_MONTH).let { day ->
if (day in 4..20) "th"
else
when (day % 10) {
1 -> "st"
2 -> "nd"
3 -> "rd"
else -> "th"
}
}
}
return SimpleDateFormat("d'$suffix' MMM''yy").format(this)
}
fun moneyFormat(amount: String): String {
return if (amount.isNotBlank()) {
val formatter = DecimalFormat("##,##,##,##,###.##")
@@ -404,14 +355,6 @@ fun <T, K, R> LiveData<T>.combineWith(liveData: LiveData<K>, block: (T?, K?) ->
return result
}
fun isSameListResponse(newResponse: FundListResponse?, oldResponse: FundListResponse?): Boolean {
if (newResponse.isNull() || oldResponse.isNull()) return false
val gson = Gson()
return gson.toJson(newResponse?.header).equals(gson.toJson(oldResponse?.header)) &&
gson.toJson(newResponse?.listOfWidgets).equals(gson.toJson(oldResponse?.listOfWidgets)) &&
gson.toJson(newResponse?.footer).equals(gson.toJson(oldResponse?.footer))
}
fun isSameListResponse(
newResponse: AmcWebLandingPageResponse?,
oldResponse: AmcWebLandingPageResponse?
@@ -430,14 +373,6 @@ fun getFundExtraData(bundle: Bundle?): FundExtraData {
)
}
fun getFundListBundle(data: Bundle?): Bundle {
val bundle = data ?: Bundle()
bundle.putString(Constant.V2, TRUE)
bundle.putString(Constant.FUND_CATEGORY, SubPageStatusType.FUND_LANDING)
bundle.putString(Constant.IS_INVESTMENT_ON_BOTTOM_NAV, TRUE)
return bundle
}
fun showTimerInFormat(
label: LabelData?,
time: Long,

View File

@@ -10,17 +10,29 @@ package com.navi.amc.utils
import com.navi.amc.common.model.CheckerResponse
import com.navi.amc.kyc.model.BankDetailsResponse
/*
* TODO Will remove this file
*/
object TempStorageHelper {
var bankDetailsResponse: BankDetailsResponse? = null
var checkerResponse: CheckerResponse? = null
var kycSourceInfo: Map<String, String>? = null
private var currentScreenName: String? = null
private var previousScreenName: String? = null
fun clear() {
bankDetailsResponse = null
checkerResponse = null
kycSourceInfo = null
}
fun updateScreenNames(newScreenName: String) {
if (newScreenName != currentScreenName) {
previousScreenName = currentScreenName
currentScreenName = newScreenName
}
}
fun setPreviousScreenName(previousScreenName: String) {
this.previousScreenName = previousScreenName
}
fun getPreviousScreenName(): String? = this.previousScreenName
}

View File

@@ -1,59 +0,0 @@
/*
*
* * Copyright © 2024 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
import android.os.CountDownTimer
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
class LifecycleAwareCountdownTimer(
private val lifecycle: Lifecycle,
private val millisInFuture: Long,
private val onTick: (Long) -> Unit,
private val onFinish: (Long) -> Unit,
private val removeOnResume: Boolean = false
) : LifecycleObserver {
private var countDownTimer: CountDownTimer? = null
private var isTimerRunning = false
init {
lifecycle.addObserver(this)
}
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun startTimer() {
if (isTimerRunning.not()) {
countDownTimer =
object : CountDownTimer(millisInFuture - System.currentTimeMillis(), 1000) {
override fun onTick(millisUntilFinished: Long) {
isTimerRunning = true
onTick.invoke(millisUntilFinished)
}
override fun onFinish() {
onFinish.invoke(0L)
}
}
.start()
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun stopTimer() {
if (removeOnResume) {
lifecycle?.removeObserver(this)
countDownTimer?.cancel()
countDownTimer = null
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
fun removeObserver() {
lifecycle?.removeObserver(this)
}
}