Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Shivam Goyal <shivam.goyal@navi.com>
1032 lines
35 KiB
Kotlin
1032 lines
35 KiB
Kotlin
/*
|
|
*
|
|
* * Copyright © 2019-2024 by Navi Technologies Limited
|
|
* * All rights reserved. Strictly confidential
|
|
*
|
|
*/
|
|
|
|
package com.naviapp.utils
|
|
|
|
import android.app.Activity
|
|
import android.app.ActivityManager
|
|
import android.content.ClipData
|
|
import android.content.ClipboardManager
|
|
import android.content.ComponentName
|
|
import android.content.Context
|
|
import android.content.ContextWrapper
|
|
import android.content.Intent
|
|
import android.content.res.Resources
|
|
import android.graphics.Color
|
|
import android.graphics.drawable.Drawable
|
|
import android.net.ConnectivityManager
|
|
import android.net.Uri
|
|
import android.os.Build
|
|
import android.os.Bundle
|
|
import android.os.CountDownTimer
|
|
import android.os.Handler
|
|
import android.os.Parcelable
|
|
import android.os.Process
|
|
import android.telephony.PhoneNumberUtils
|
|
import android.text.TextUtils
|
|
import android.view.View
|
|
import android.view.ViewTreeObserver
|
|
import android.view.inputmethod.InputMethodManager
|
|
import android.widget.EditText
|
|
import android.widget.ImageView
|
|
import androidx.compose.runtime.Composable
|
|
import androidx.compose.runtime.DisposableEffect
|
|
import androidx.compose.runtime.State
|
|
import androidx.compose.runtime.mutableStateOf
|
|
import androidx.compose.runtime.remember
|
|
import androidx.compose.ui.platform.LocalView
|
|
import androidx.core.util.PatternsCompat
|
|
import androidx.core.view.ViewCompat
|
|
import androidx.core.view.WindowInsetsCompat
|
|
import androidx.fragment.app.FragmentActivity
|
|
import androidx.work.WorkManager
|
|
import com.bumptech.glide.Glide
|
|
import com.bumptech.glide.load.DataSource
|
|
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
|
import com.bumptech.glide.load.engine.GlideException
|
|
import com.bumptech.glide.request.RequestListener
|
|
import com.bumptech.glide.request.target.Target
|
|
import com.google.android.material.card.MaterialCardView
|
|
import com.google.gson.Gson
|
|
import com.google.gson.GsonBuilder
|
|
import com.navi.amc.common.taskProcessor.AmcTaskManager
|
|
import com.navi.amc.navigator.NaviAmcDeeplinkNavigator
|
|
import com.navi.ap.utils.registerApUiTronDeSerializers
|
|
import com.navi.base.model.ClickableTextType
|
|
import com.navi.base.model.CtaData
|
|
import com.navi.base.model.EmailSubjectBodyResponse
|
|
import com.navi.base.model.LineItem
|
|
import com.navi.base.model.PhoneNumberResponse
|
|
import com.navi.base.sharedpref.PreferenceManager
|
|
import com.navi.base.utils.BaseUtils
|
|
import com.navi.base.utils.isNotNullAndNotEmpty
|
|
import com.navi.base.utils.isNull
|
|
import com.navi.base.utils.orFalse
|
|
import com.navi.base.utils.orTrue
|
|
import com.navi.base.utils.orZero
|
|
import com.navi.common.juspay.HyperServicesHolder
|
|
import com.navi.common.model.ModuleNameV2
|
|
import com.navi.common.network.models.GenericErrorResponse
|
|
import com.navi.common.uitron.model.action.UploadDataConfig
|
|
import com.navi.common.uitron.serializer.UiTronActionSerializer
|
|
import com.navi.common.uitron.serializer.UiTronTriggerApiActionSerializer
|
|
import com.navi.common.uitron.serializer.UiTronUploadDataSerializer
|
|
import com.navi.common.utils.CommonNaviAnalytics
|
|
import com.navi.common.utils.Constants.LOGIN_SOURCE
|
|
import com.navi.common.utils.EmiCalculator
|
|
import com.navi.common.utils.TemporaryStorageHelper
|
|
import com.navi.common.utils.log
|
|
import com.navi.design.utils.isValidHexColor
|
|
import com.navi.insurance.navigator.NaviInsuranceDeeplinkNavigator
|
|
import com.navi.insurance.sharedpref.NaviPreferenceManager
|
|
import com.navi.naviwidgets.WidgetDataDeserializer
|
|
import com.navi.naviwidgets.models.GenericWidgetDataInfo
|
|
import com.navi.naviwidgets.models.NaviWidget
|
|
import com.navi.naviwidgets.models.ParameterValue
|
|
import com.navi.naviwidgets.models.response.CardProperties
|
|
import com.navi.naviwidgets.utils.setCardProperties
|
|
import com.navi.naviwidgets.validations.BaseInputValidation
|
|
import com.navi.naviwidgets.validations.ValidationJsonDeserializer
|
|
import com.navi.naviwidgets.widgets.NaviWidgetJsonDeserializer
|
|
import com.navi.naviwidgets.widgets.NaviWidgetJsonSerializer
|
|
import com.navi.naviwidgets.widgets.ParameterValueJsonDeserializer
|
|
import com.navi.pay.common.utils.getExcludeSecureSharedPrefKeys
|
|
import com.navi.pay.common.utils.getExcludeSharedPrefKeys
|
|
import com.navi.uitron.model.action.TriggerApiAction
|
|
import com.navi.uitron.model.animations.AnimationSpec
|
|
import com.navi.uitron.model.animations.PropertyAnimator
|
|
import com.navi.uitron.model.data.UiTronAction
|
|
import com.navi.uitron.model.data.UiTronData
|
|
import com.navi.uitron.model.ui.BaseProperty
|
|
import com.navi.uitron.model.visualtransformation.VisualTransformationData
|
|
import com.navi.uitron.serializer.UiTronValidationSerializer
|
|
import com.navi.uitron.serializer.VisualTransformationDataSerializer
|
|
import com.navi.uitron.serializer.animationsSerializers.AnimationSpecSerializer
|
|
import com.navi.uitron.serializer.animationsSerializers.PropertyAnimatorSerializer
|
|
import com.naviapp.BuildConfig
|
|
import com.naviapp.R
|
|
import com.naviapp.analytics.utils.NaviAnalytics
|
|
import com.naviapp.analytics.utils.NaviSDKHelper
|
|
import com.naviapp.app.NaviApplication
|
|
import com.naviapp.common.deserializer.CustomHomeWidgetDataDeSerializer
|
|
import com.naviapp.common.navigator.NaviDeepLinkNavigator
|
|
import com.naviapp.common.navigator.NaviDeepLinkNavigator.ERROR_V2
|
|
import com.naviapp.common.navigator.NaviDeepLinkNavigator.getPersonalLoanDynamicModuleIntent
|
|
import com.naviapp.common.serializer.CustomHomeWidgetDataSerializer
|
|
import com.naviapp.home.activity.OnBoardingActivity
|
|
import com.naviapp.home.compose.uiTron.model.deserializer.HomeUitronPropertyDeserializer
|
|
import com.naviapp.home.compose.uiTron.model.serializer.HomeUitronPropertySerializer
|
|
import com.naviapp.home.dashboard.models.response.DashboardContentResponse
|
|
import com.naviapp.manager.usecase.UserDataUploadWorkerUseCase
|
|
import com.naviapp.models.ColorData
|
|
import com.naviapp.models.RedirectPageStatus
|
|
import com.naviapp.models.response.WidgetConfig
|
|
import com.naviapp.models.response.WidgetConfigLayoutParams
|
|
import com.naviapp.permission.fragments.MandatePermissionFragment
|
|
import com.naviapp.personalloanrevamp.models.response.BottomSheetConfig
|
|
import com.naviapp.registration.RegistrationActivity
|
|
import com.naviapp.utils.Constants.ERROR_DATA
|
|
import com.naviapp.utils.Constants.HYPERVERGE_FILES_PATH
|
|
import com.naviapp.utils.Constants.INDIAN_COUNTRY_CODE
|
|
import com.naviapp.utils.Constants.MINIMUM_NUMBER_OF_CHARACTERS_IN_NAME
|
|
import com.naviapp.utils.Constants.PLAY_STORE_REQUEST_CODE
|
|
import com.naviapp.utils.Constants.REDIRECT_DATA
|
|
import com.naviapp.utils.Constants.REDIRECT_STATUS
|
|
import com.naviapp.utils.Constants.UTF_8
|
|
import com.naviapp.utils.Constants.VALID_NAME_REGEX
|
|
import com.naviapp.utils.Constants.VALID_PHONE_NUMBER_LENGTH
|
|
import com.naviapp.utils.Constants.WHATSAPP_URI
|
|
import com.naviapp.utils.Constants.WHATSAPP_URI_TEXT
|
|
import java.io.File
|
|
import java.io.IOException
|
|
import java.io.Serializable
|
|
import java.math.BigDecimal
|
|
import java.math.RoundingMode
|
|
import java.net.URLEncoder
|
|
import java.text.DecimalFormat
|
|
import java.util.Calendar
|
|
import java.util.UUID
|
|
import java.util.regex.Pattern
|
|
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
|
import okhttp3.MultipartBody
|
|
import okhttp3.RequestBody
|
|
import okhttp3.RequestBody.Companion.toRequestBody
|
|
import org.joda.money.BigMoney
|
|
import org.joda.money.CurrencyUnit
|
|
import org.joda.time.LocalDate
|
|
import org.json.JSONException
|
|
import org.json.JSONObject
|
|
|
|
fun getAppName(): String {
|
|
return if (TextUtils.equals(BuildConfig.FLAVOR, PROD)) Constants.APP_NAME_PROD
|
|
else Constants.APP_NAME_DEBUG
|
|
}
|
|
|
|
fun deleteCacheAndOpenLoginPage(context: Context = NaviApplication.instance) {
|
|
try {
|
|
if (BaseUtils.isUserLoggedIn()) {
|
|
BaseUtils.saveCurrentExternalCustomerId(BaseUtils.getExternalCustomerId().orEmpty())
|
|
TemporaryStorageHelper.clear()
|
|
AmcTaskManager.clearData(true)
|
|
clearData()
|
|
clearHypervergeData()
|
|
val intent = Intent(context, RegistrationActivity::class.java)
|
|
intent.addFlags(
|
|
Intent.FLAG_ACTIVITY_CLEAR_TASK or
|
|
Intent.FLAG_ACTIVITY_NEW_TASK or
|
|
Intent.FLAG_ACTIVITY_SINGLE_TOP
|
|
)
|
|
intent.putExtra(LOGIN_SOURCE, Constants.DEFAULT_LOGIN_SOURCE_FOR_WHATSAPP_LOGIN)
|
|
NaviSDKHelper.logoutUser(context)
|
|
NaviApplication.instance.applicationContext.startActivity(intent)
|
|
stopActiveWorkers(
|
|
context,
|
|
listOf(UserDataUploadWorkerUseCase.PERIODIC_USER_UPLOAD_WORKER_TAG)
|
|
)
|
|
}
|
|
} catch (ignored: Exception) {
|
|
ignored.log()
|
|
}
|
|
}
|
|
|
|
fun stopActiveWorkers(context: Context, tags: List<String>?) {
|
|
try {
|
|
tags?.forEach { tag -> WorkManager.getInstance(context).cancelAllWorkByTag(tag) }
|
|
} catch (e: Exception) {
|
|
e.log()
|
|
}
|
|
}
|
|
|
|
fun clearHypervergeData() {
|
|
try {
|
|
val file =
|
|
File(
|
|
ContextWrapper(NaviApplication.instance).applicationInfo.dataDir +
|
|
HYPERVERGE_FILES_PATH
|
|
)
|
|
if (file.exists()) {
|
|
file.deleteRecursively()
|
|
}
|
|
} catch (e: IOException) {
|
|
e.printStackTrace()
|
|
}
|
|
}
|
|
|
|
fun handleError(errors: List<GenericErrorResponse>?, redirectPageStatus: RedirectPageStatus?) {
|
|
val context = NaviApplication.instance.applicationContext
|
|
val intent = getPersonalLoanDynamicModuleIntent(context = context, url = ERROR_V2)
|
|
intent.putExtra(ERROR_DATA, errors?.firstOrNull())
|
|
intent.putExtra(REDIRECT_DATA, redirectPageStatus)
|
|
intent.addFlags(
|
|
Intent.FLAG_ACTIVITY_CLEAR_TASK or
|
|
Intent.FLAG_ACTIVITY_NEW_TASK or
|
|
Intent.FLAG_ACTIVITY_SINGLE_TOP
|
|
)
|
|
context.startActivity(intent)
|
|
}
|
|
|
|
fun isNetworkAvailable(): Boolean {
|
|
val connectivityManager =
|
|
NaviApplication.instance.getSystemService(Context.CONNECTIVITY_SERVICE)
|
|
as? ConnectivityManager
|
|
return connectivityManager?.activeNetworkInfo?.isConnected.orFalse()
|
|
}
|
|
|
|
fun clearData() {
|
|
PreferenceManager.clearPrefDataSession(
|
|
excludeSharedPrefKeys = getExcludeSharedPrefKeys(),
|
|
excludeSecureSharedPrefKeys = getExcludeSecureSharedPrefKeys()
|
|
)
|
|
NaviPreferenceManager.clearDataOnLogout()
|
|
HyperServicesHolder.onLogout { log ->
|
|
val naviAnalyticsEventTracker = NaviAnalytics.naviAnalytics.Dashboard()
|
|
naviAnalyticsEventTracker.jusPayAdditionalTracking(log)
|
|
}
|
|
}
|
|
|
|
fun isDead(activity: Activity?): Boolean {
|
|
return activity == null || activity.isFinishing
|
|
}
|
|
|
|
fun CharSequence?.isValidEmail() =
|
|
!this.isNullOrEmpty() && PatternsCompat.EMAIL_ADDRESS.matcher(this).matches()
|
|
|
|
fun String.isValidPhoneNumber() = length == VALID_PHONE_NUMBER_LENGTH && all { it.isDigit() }
|
|
|
|
fun String.isValidName() =
|
|
this.trim().length >= MINIMUM_NUMBER_OF_CHARACTERS_IN_NAME &&
|
|
VALID_NAME_REGEX.toRegex().matches(this.trim())
|
|
|
|
fun EditText.openKeyboard(context: Context, delay: Long = 100) {
|
|
try {
|
|
Handler()
|
|
.postDelayed(
|
|
{
|
|
requestFocus()
|
|
setSelection(length())
|
|
(context.getSystemService(Activity.INPUT_METHOD_SERVICE) as? InputMethodManager)
|
|
?.apply {
|
|
showSoftInput(this@openKeyboard, InputMethodManager.SHOW_IMPLICIT)
|
|
}
|
|
},
|
|
delay
|
|
)
|
|
} catch (e: Exception) {
|
|
e.log()
|
|
}
|
|
}
|
|
|
|
fun dpToPx(inpDp: Int): Int {
|
|
return (inpDp * Resources.getSystem().displayMetrics.density).toInt()
|
|
}
|
|
|
|
fun pxToDp(px: Int) = px.div(Resources.getSystem().displayMetrics.density).toInt()
|
|
|
|
fun String.getOrdinal(): String {
|
|
val number = this.toInt()
|
|
val suffixes = arrayOf("th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th")
|
|
return when (number % 100) {
|
|
11,
|
|
12,
|
|
13 -> this + "th"
|
|
else -> this + suffixes[number % 10]
|
|
}
|
|
}
|
|
|
|
fun getMultipartRequestBody(content: String): RequestBody {
|
|
return RequestBody.create("text/plain".toMediaTypeOrNull(), content)
|
|
}
|
|
|
|
fun getMultipartBody(
|
|
bytes: ByteArray,
|
|
fileName: String,
|
|
name: String = "file"
|
|
): MultipartBody.Part {
|
|
val reqFile = bytes.toRequestBody("image/jpeg".toMediaTypeOrNull(), 0, bytes.size)
|
|
return MultipartBody.Part.createFormData(name, fileName, reqFile)
|
|
}
|
|
|
|
fun getMultipartRequestJsonBody(content: String): RequestBody {
|
|
return RequestBody.create("application/json".toMediaTypeOrNull(), content)
|
|
}
|
|
|
|
fun cacheDirUri(fileName: String): String {
|
|
return "file://${NaviApplication.instance.applicationContext?.externalCacheDir?.path}/$fileName"
|
|
}
|
|
|
|
fun showRatingWidget(view: View, activity: Activity?) {
|
|
Handler()
|
|
.postDelayed(
|
|
{
|
|
if (activity?.isDestroyed.orTrue() || activity?.isFinishing.orTrue())
|
|
return@postDelayed
|
|
slideInTop(view)
|
|
},
|
|
Constants.RATING_WIDGET_SHOW_AFTER_SEC
|
|
)
|
|
}
|
|
|
|
fun hideRatingWidget(view: View, activity: Activity?) {
|
|
Handler()
|
|
.postDelayed(
|
|
{
|
|
if (activity?.isDestroyed.orTrue() || activity?.isFinishing.orTrue())
|
|
return@postDelayed
|
|
view.visibility = View.GONE
|
|
},
|
|
Constants.RATING_WIDGET_SHOW_AFTER_SEC
|
|
)
|
|
}
|
|
|
|
fun openPlayStore(
|
|
activity: Activity,
|
|
pkgName: String = getPackgName(),
|
|
requestCode: Int = PLAY_STORE_REQUEST_CODE
|
|
) {
|
|
try {
|
|
activity.startActivityForResult(
|
|
Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=$pkgName")),
|
|
requestCode
|
|
)
|
|
} catch (e: android.content.ActivityNotFoundException) {
|
|
activity.startActivityForResult(
|
|
Intent(
|
|
Intent.ACTION_VIEW,
|
|
Uri.parse("https://play.google.com/store/apps/details?id=$pkgName")
|
|
),
|
|
requestCode
|
|
)
|
|
e.log()
|
|
} finally {}
|
|
}
|
|
|
|
private fun getPackgName(): String {
|
|
try {
|
|
return NaviApplication.instance.applicationContext.packageName
|
|
} catch (e: Exception) {
|
|
return "com.naviapp"
|
|
}
|
|
}
|
|
|
|
fun <T> convertObjectToJsonString(type: T): String? {
|
|
val gson = Gson()
|
|
val jsonString = gson.toJson(type)
|
|
try {
|
|
return jsonString
|
|
} catch (e: JSONException) {}
|
|
return null
|
|
}
|
|
|
|
fun convertStringToInt(data: String): Int {
|
|
try {
|
|
if (data.isBlank()) return -1
|
|
return data.toInt()
|
|
} catch (e: Exception) {
|
|
e.log()
|
|
}
|
|
return 0
|
|
}
|
|
|
|
fun validateDate(day: Int, month: Int, year: Int): Boolean {
|
|
if (day < 1 || month < 1 || day > 31 || month > 12)
|
|
return false // Year validation needs to be done
|
|
|
|
if (day == 31 && (month == 4 || month == 6 || month == 9 || month == 11)) {
|
|
return false // only 1,3,5,7,8,10,12 has 31 days
|
|
} else if (month == 2) {
|
|
// leap year
|
|
if (year.rem(4) == 0) {
|
|
if (day == 30 || day == 31) {
|
|
return false
|
|
}
|
|
} else {
|
|
if (day == 29 || day == 30 || day == 31) {
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
return isValidYear(year)
|
|
}
|
|
|
|
fun validateMonthAndYear(month: Int, year: Int): Boolean {
|
|
if (month < 1 || month > 12) return false
|
|
return isValidYear(year)
|
|
}
|
|
|
|
fun isValidYear(year: Int): Boolean {
|
|
try {
|
|
return year <= Calendar.getInstance().get(Calendar.YEAR)
|
|
} catch (e: Exception) {
|
|
e.log()
|
|
}
|
|
return true
|
|
}
|
|
|
|
fun stringToDouble(data: String?): Double {
|
|
try {
|
|
if (data == null) return 0.0
|
|
return data.toDouble()
|
|
} catch (e: Exception) {}
|
|
return 0.0
|
|
}
|
|
|
|
fun loadUrlIntoImageView(
|
|
context: Context,
|
|
url: String,
|
|
view: ImageView,
|
|
isCacheNeeded: Boolean = true,
|
|
listener: RequestListener<Drawable>? = null
|
|
) {
|
|
try {
|
|
if (isCacheNeeded)
|
|
Glide.with(context)
|
|
.load(url)
|
|
.diskCacheStrategy(DiskCacheStrategy.DATA)
|
|
.listener(
|
|
listener
|
|
?: object : RequestListener<Drawable> {
|
|
override fun onLoadFailed(
|
|
e: GlideException?,
|
|
model: Any?,
|
|
target: Target<Drawable>?,
|
|
isFirstResource: Boolean
|
|
): Boolean {
|
|
CommonNaviAnalytics.naviAnalytics
|
|
.ImageLoadError()
|
|
.sendImageLoadError(url)
|
|
return false
|
|
}
|
|
|
|
override fun onResourceReady(
|
|
resource: Drawable?,
|
|
model: Any?,
|
|
target: Target<Drawable>?,
|
|
dataSource: DataSource?,
|
|
isFirstResource: Boolean
|
|
): Boolean {
|
|
return false
|
|
}
|
|
}
|
|
)
|
|
.into(view)
|
|
else Glide.with(context).load(url).into(view)
|
|
} catch (e: Exception) {}
|
|
}
|
|
|
|
fun LocalDate.isValidAgeForPersonalLoan(minAge: Int, maxAge: Int): Boolean {
|
|
try {
|
|
val age = getAge(this)
|
|
if (age in minAge until maxAge) return true
|
|
} catch (e: java.lang.Exception) {
|
|
return false
|
|
}
|
|
return false
|
|
}
|
|
|
|
fun getAge(localDate: LocalDate): Int {
|
|
val year = localDate.year
|
|
val month = localDate.monthOfYear
|
|
val day = localDate.dayOfMonth
|
|
val dob = Calendar.getInstance()
|
|
dob[year, month - 1] = day
|
|
val today = Calendar.getInstance()
|
|
var age = today[Calendar.YEAR] - dob[Calendar.YEAR]
|
|
if (today[Calendar.DAY_OF_YEAR] < dob[Calendar.DAY_OF_YEAR]) {
|
|
age--
|
|
}
|
|
return age
|
|
}
|
|
|
|
fun String.isValidPan(): Boolean {
|
|
if (this.length == Constants.VALID_PAN_LENGTH) {
|
|
val panPattern = Pattern.compile(Constants.PAN_REGEX)
|
|
if (panPattern.matcher(this).matches()) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
fun openWhatsAppChatConversation(context: Context?, numberWithCountryCode: String?) {
|
|
if (numberWithCountryCode.isNullOrBlank()) return
|
|
context?.let {
|
|
if (isAppInstalled(it, Constants.WhatsAppPkg)) openWhatsAppChat(it, numberWithCountryCode)
|
|
}
|
|
}
|
|
|
|
private fun openWhatsAppChat(context: Context, numberWithCountryCode: String) {
|
|
var number = numberWithCountryCode
|
|
try {
|
|
number = number.replace(" ", "").replace("+", "")
|
|
val sendIntent = Intent("android.intent.action.MAIN")
|
|
sendIntent.component =
|
|
ComponentName(Constants.WhatsAppPkg, Constants.WhatsAppPkgConversation)
|
|
sendIntent.putExtra(
|
|
"jid",
|
|
PhoneNumberUtils.stripSeparators(number).toString() + "@s.whatsapp.net"
|
|
)
|
|
context.startActivity(sendIntent)
|
|
} catch (e: Exception) {
|
|
openWhatsAppConversationUsingUri(context, numberWithCountryCode)
|
|
}
|
|
}
|
|
|
|
private fun openWhatsAppConversationUsingUri(context: Context, numberWithCountryCode: String) {
|
|
try {
|
|
val uri = Uri.parse("https://api.whatsapp.com/send?phone=$numberWithCountryCode")
|
|
val sendIntent = Intent(Intent.ACTION_VIEW, uri)
|
|
context.startActivity(sendIntent)
|
|
} catch (e: Exception) {
|
|
e.log()
|
|
}
|
|
}
|
|
|
|
fun isAppInstalled(context: Context, pkgName: String): Boolean {
|
|
try {
|
|
context.packageManager.getPackageInfo(pkgName, 0)
|
|
return true
|
|
} catch (e: Exception) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
fun getUniqueRandomNumber(): String? {
|
|
try {
|
|
return UUID.randomUUID().toString()
|
|
} catch (e: Exception) {}
|
|
return null
|
|
}
|
|
|
|
fun getLocalTimeStamp(): Long {
|
|
val rightNow: Calendar = Calendar.getInstance()
|
|
val offset: Long =
|
|
(rightNow.get(Calendar.ZONE_OFFSET) + rightNow.get(Calendar.DST_OFFSET)).toLong()
|
|
return rightNow.timeInMillis + offset
|
|
}
|
|
|
|
fun extractData(data: Map<String, Any?>?, loginSource: String?): Bundle {
|
|
val bundle = Bundle()
|
|
loginSource?.let { bundle.putString(LOGIN_SOURCE, it) }
|
|
data?.forEach { (key, value) ->
|
|
try {
|
|
when (value) {
|
|
is Boolean -> bundle.putBoolean(key, value)
|
|
is String -> bundle.putString(key, value)
|
|
is Int -> bundle.putInt(key, value)
|
|
is Double -> bundle.putDouble(key, value)
|
|
is Float -> bundle.putFloat(key, value)
|
|
is Parcelable -> bundle.putParcelable(key, value)
|
|
is Serializable -> bundle.putSerializable(key, value)
|
|
}
|
|
} catch (ex: Exception) {}
|
|
}
|
|
return bundle
|
|
}
|
|
|
|
fun getTotalValue(list: List<ColorData>?): Int {
|
|
var sum = 0
|
|
list?.forEach { sum += it.value.orZero() }
|
|
return sum
|
|
}
|
|
|
|
private fun amcDeeplink(deeplink: String): String {
|
|
return NaviAmcDeeplinkNavigator.AMC.plus(Constants.DIVIDER).plus(deeplink)
|
|
}
|
|
|
|
fun giDeeplink(deeplink: String): String {
|
|
return NaviDeepLinkNavigator.GI.plus(Constants.DIVIDER).plus(deeplink)
|
|
}
|
|
|
|
fun isPublicPage(screen: String?): Boolean {
|
|
return screen?.let {
|
|
amcDeeplink(NaviAmcDeeplinkNavigator.HOME).equals(it, ignoreCase = true) ||
|
|
amcDeeplink(NaviAmcDeeplinkNavigator.ALL_FUNDS).equals(it, ignoreCase = true) ||
|
|
giDeeplink(NaviInsuranceDeeplinkNavigator.CHAT).equals(it, ignoreCase = true) ||
|
|
NaviDeepLinkNavigator.HOME.equals(it, ignoreCase = true)
|
|
} ?: run { false }
|
|
}
|
|
|
|
fun extractData(jsonObject: JSONObject?): Bundle {
|
|
val bundle = Bundle()
|
|
jsonObject?.keys()?.forEach { key ->
|
|
val value = jsonObject.opt(key)
|
|
try {
|
|
when (value) {
|
|
is Boolean -> bundle.putBoolean(key, value)
|
|
is String -> bundle.putString(key, value)
|
|
is Int -> bundle.putInt(key, value)
|
|
is Double -> bundle.putDouble(key, value)
|
|
is Float -> bundle.putFloat(key, value)
|
|
is Parcelable -> bundle.putParcelable(key, value)
|
|
is Serializable -> bundle.putSerializable(key, value)
|
|
}
|
|
} catch (ex: Exception) {}
|
|
}
|
|
return bundle
|
|
}
|
|
|
|
fun extractData(uri: Uri?): Bundle {
|
|
val bundle = Bundle()
|
|
uri?.queryParameterNames?.forEach { key -> bundle.putString(key, uri.getQueryParameter(key)) }
|
|
return bundle
|
|
}
|
|
|
|
fun extractQueryParams(link: String?): String? {
|
|
return try {
|
|
val uri = Uri.parse(link)
|
|
val json = JSONObject()
|
|
uri?.queryParameterNames?.forEach { key -> json.put(key, uri.getQueryParameter(key)) }
|
|
return Gson().toJson(json)
|
|
} catch (_: java.lang.Exception) {
|
|
null
|
|
}
|
|
}
|
|
|
|
fun getQueryParamsFromCta(cta: CtaData?): HashMap<String, String> {
|
|
val queryMap = HashMap<String, String>()
|
|
cta?.parameters?.forEach { item -> item.key?.let { key -> queryMap[key] = "${item.value}" } }
|
|
return queryMap
|
|
}
|
|
|
|
fun sendEmail(activity: Activity, emailSubjectBodyResponse: EmailSubjectBodyResponse) {
|
|
try {
|
|
val selectorIntent = Intent(Intent.ACTION_SENDTO)
|
|
selectorIntent.data = Uri.parse("mailto:")
|
|
val intent = Intent(Intent.ACTION_SEND)
|
|
intent.putExtra(
|
|
Intent.EXTRA_EMAIL,
|
|
emailSubjectBodyResponse.recipientEmailIds?.toTypedArray()
|
|
)
|
|
intent.putExtra(Intent.EXTRA_SUBJECT, emailSubjectBodyResponse.subject)
|
|
intent.putExtra(Intent.EXTRA_TEXT, emailSubjectBodyResponse.body)
|
|
intent.selector = selectorIntent
|
|
activity.startActivity(Intent.createChooser(intent, "Send E-mail"))
|
|
} catch (e: Exception) {
|
|
e.log()
|
|
}
|
|
}
|
|
|
|
fun openCallDialer(mobileNo: String?, activity: Activity?) {
|
|
mobileNo?.let {
|
|
val uri = Uri.parse("tel:$mobileNo")
|
|
val intent = Intent(Intent.ACTION_DIAL, uri)
|
|
try {
|
|
activity?.startActivity(intent)
|
|
} catch (ex: Exception) {
|
|
ex.printStackTrace()
|
|
}
|
|
}
|
|
}
|
|
|
|
fun navigateToClickableText(activity: Activity?, type: String?, data: Any?) {
|
|
when (type) {
|
|
ClickableTextType.EMAIL.name -> {
|
|
val emailResponseData =
|
|
Gson().fromJson(Gson().toJson(data), EmailSubjectBodyResponse::class.java)
|
|
emailResponseData?.let { response -> activity?.let { sendEmail(activity, response) } }
|
|
}
|
|
ClickableTextType.PHONE.name -> {
|
|
val phoneResponseData =
|
|
Gson().fromJson(Gson().toJson(data), PhoneNumberResponse::class.java)
|
|
phoneResponseData?.number?.let { openCallDialer(it, activity) }
|
|
}
|
|
ClickableTextType.DEEPLINK.name -> {
|
|
val ctaData = Gson().fromJson(Gson().toJson(data), CtaData::class.java)
|
|
ctaData?.url?.let { NaviDeepLinkNavigator.navigate(activity, ctaData) }
|
|
}
|
|
}
|
|
}
|
|
|
|
fun sendMessageToWhatsapp(message: String, number: String, activity: FragmentActivity) {
|
|
try {
|
|
activity.startActivity(
|
|
Intent(
|
|
Intent.ACTION_VIEW,
|
|
Uri.parse(
|
|
WHATSAPP_URI + number + WHATSAPP_URI_TEXT + URLEncoder.encode(message, UTF_8)
|
|
)
|
|
)
|
|
)
|
|
} catch (e: Exception) {
|
|
e.log()
|
|
}
|
|
}
|
|
|
|
fun getNumberWithoutCountryCode(phoneNumber: String): String {
|
|
var number = phoneNumber.replace(SPACE, EMPTY)
|
|
number = number.replace(MINUS, EMPTY)
|
|
number = number.replace("(", EMPTY)
|
|
number = number.replace(")", EMPTY)
|
|
number =
|
|
if (number.length > VALID_PHONE_NUMBER_LENGTH) {
|
|
number.takeLast(VALID_PHONE_NUMBER_LENGTH)
|
|
} else {
|
|
number
|
|
}
|
|
return number
|
|
}
|
|
|
|
fun getPhoneWithCountryCode(number: String): String {
|
|
return INDIAN_COUNTRY_CODE + number
|
|
}
|
|
|
|
fun postTaskWithDelay(delay: Long, action: () -> Unit) {
|
|
Handler().postDelayed(action, delay)
|
|
}
|
|
|
|
fun formatSecToMin(second: Long): String {
|
|
val min = second / 60
|
|
val sec = second % 60
|
|
if (min < 10 && sec < 10) return "0$min:0$sec"
|
|
if (min < 10) return "0$min:$sec"
|
|
if (sec < 10) return "$min:0$sec"
|
|
return "$min:$sec"
|
|
}
|
|
|
|
fun getTimer(
|
|
timeInSeconds: Long,
|
|
onTick: ((timeRemaining: String) -> Unit)? = null,
|
|
onFinish: (() -> Unit)? = null
|
|
): CountDownTimer {
|
|
return object : CountDownTimer(timeInSeconds * 1000L, 1000) {
|
|
override fun onTick(millisUntilFinished: Long) {
|
|
onTick?.invoke(formatSecToMin(millisUntilFinished / 1000))
|
|
}
|
|
|
|
override fun onFinish() {
|
|
onFinish?.invoke()
|
|
}
|
|
}
|
|
}
|
|
|
|
fun getLendingModuleNameFromWidgetId(widgetId: String?): ModuleNameV2 {
|
|
return when (widgetId) {
|
|
Constants.PERSONAL_LOAN -> ModuleNameV2.PL
|
|
Constants.HOME_LOAN -> ModuleNameV2.HL
|
|
else -> ModuleNameV2.COMMON
|
|
}
|
|
}
|
|
|
|
fun getEmiValue(amount: Double, rateOfInterest: Double, tenure: Int): BigDecimal? {
|
|
val emi =
|
|
EmiCalculator(
|
|
BigMoney.of(CurrencyUnit.of(Constants.INR), amount),
|
|
BigDecimal.valueOf(rateOfInterest),
|
|
tenure
|
|
)
|
|
.calculate()
|
|
return emi?.amount
|
|
?.divide(BigDecimal.ONE)
|
|
?.setScale(0, RoundingMode.HALF_UP)
|
|
?.multiply(BigDecimal.ONE)
|
|
}
|
|
|
|
val decimalFormat: DecimalFormat = DecimalFormat("##,##,##,##,###.##")
|
|
|
|
fun extractObjectDataToStringMap(jsonObject: JSONObject?): Map<String, String> {
|
|
var objectMap: MutableMap<String, String> = mutableMapOf()
|
|
jsonObject?.keys()?.forEach { key ->
|
|
val value = jsonObject.opt(key)
|
|
try {
|
|
when (value) {
|
|
is String -> {
|
|
objectMap[key] = value
|
|
}
|
|
is Boolean,
|
|
Int,
|
|
Double,
|
|
Float -> {
|
|
objectMap[key] = value.toString()
|
|
}
|
|
else -> objectMap[key] = Gson().toJson(value)
|
|
}
|
|
} catch (ex: Exception) {}
|
|
}
|
|
return objectMap
|
|
}
|
|
|
|
fun getMapFromJsonAndPair(
|
|
jsonObject: JSONObject?,
|
|
vararg pairs: Pair<String, String>?
|
|
): Map<String, String> {
|
|
val metaDataMap = mutableMapOf<String, String>()
|
|
pairs?.forEach { pair -> pair?.let { metaDataMap[pair.first] = pair.second } }
|
|
val extraDataMap = extractObjectDataToStringMap(jsonObject)
|
|
if (extraDataMap.isNotEmpty()) {
|
|
metaDataMap.putAll(extraDataMap)
|
|
}
|
|
return metaDataMap
|
|
}
|
|
|
|
fun copyText(context: Context?, text: String?) {
|
|
context?.let { nonNullContext ->
|
|
text?.let {
|
|
val clipboard =
|
|
nonNullContext.getSystemService(Context.CLIPBOARD_SERVICE) as? ClipboardManager
|
|
val clip: ClipData = ClipData.newPlainText(it, it)
|
|
clipboard?.setPrimaryClip(clip)
|
|
nonNullContext.toast(R.string.copied)
|
|
}
|
|
}
|
|
}
|
|
|
|
fun bundleToJson(bundle: Bundle?): String {
|
|
try {
|
|
val json = JSONObject()
|
|
bundle?.keySet()?.forEach { key -> json.put(key, bundle.get(key)) }
|
|
return Gson().toJson(json)
|
|
} catch (_: java.lang.Exception) {}
|
|
return EMPTY
|
|
}
|
|
|
|
fun constructBundleWithCtaData(ctaData: CtaData?, bundle: Bundle?): Bundle =
|
|
(bundle ?: Bundle()).apply { putParcelable(Constants.KEY_CTA, ctaData) }
|
|
|
|
fun isSameDashboardResponse(
|
|
newResponse: DashboardContentResponse?,
|
|
oldResponse: DashboardContentResponse?
|
|
): Boolean {
|
|
if (newResponse.isNull() || oldResponse.isNull()) return false
|
|
val gson = Gson()
|
|
return gson
|
|
.toJson(newResponse?.listOfWidgets)
|
|
.equals(gson.toJson(oldResponse?.listOfWidgets)) &&
|
|
gson.toJson(newResponse?.metaData).equals(gson.toJson(oldResponse?.metaData))
|
|
}
|
|
|
|
fun setCardPropertiesFromWidgetLayoutParams(
|
|
materialCardView: MaterialCardView,
|
|
widgetLayoutParams: WidgetConfigLayoutParams?
|
|
) {
|
|
widgetLayoutParams?.let {
|
|
materialCardView.setCardProperties(
|
|
CardProperties(
|
|
strokeColor = widgetLayoutParams.borderColor,
|
|
strokeWidth = widgetLayoutParams.borderWidth.orZero(),
|
|
borderRadius = widgetLayoutParams.borderRadius.orZero(),
|
|
elevation = widgetLayoutParams.elevation,
|
|
backgroundColor = widgetLayoutParams.backgroundColor
|
|
)
|
|
)
|
|
widgetLayoutParams.shadowColor?.let {
|
|
if (isValidHexColor(it)) {
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
|
materialCardView.outlineSpotShadowColor = Color.parseColor(it)
|
|
materialCardView.outlineAmbientShadowColor = Color.parseColor(it)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fun getWidgetPositionFromWidgetId(widgets: List<WidgetConfig>, id: String?): Int? {
|
|
widgets.forEachIndexed { index, widgetConfig ->
|
|
if (widgetConfig.widgetId == id) {
|
|
return index
|
|
}
|
|
}
|
|
return null
|
|
}
|
|
|
|
fun isDifferentPackage(context: Context): Boolean {
|
|
val currentProcess = getCurrentProcess(context)
|
|
return currentProcess != context.packageName
|
|
}
|
|
|
|
fun getCurrentProcess(context: Context): String? {
|
|
try {
|
|
val am = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
|
|
val processInfos = am.runningAppProcesses ?: emptyList()
|
|
val myPid = Process.myPid()
|
|
for (info in processInfos) {
|
|
if (info.pid == myPid) {
|
|
return info.processName
|
|
}
|
|
}
|
|
} catch (e: Exception) {}
|
|
return null
|
|
}
|
|
|
|
fun isBottomSheetEnabled(type: String, bottomSheetList: List<BottomSheetConfig>?): Boolean {
|
|
bottomSheetList?.forEach {
|
|
if (it.type != null && it.type == type) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
fun launchPermissionActivity(
|
|
activity: Activity,
|
|
addIntentFlags: Boolean = false,
|
|
finish: Boolean = true,
|
|
normalFlow: Boolean = false,
|
|
extras: Bundle?
|
|
) {
|
|
val intent = Intent(activity, OnBoardingActivity::class.java)
|
|
extras?.let { intent.putExtras(it) }
|
|
intent.putExtra(REDIRECT_STATUS, MandatePermissionFragment.TAG)
|
|
intent.putExtra(MandatePermissionFragment.NORMAL_PERMISSION_FLOW, normalFlow)
|
|
if (addIntentFlags) {
|
|
intent.addFlags(
|
|
Intent.FLAG_ACTIVITY_NEW_TASK or
|
|
Intent.FLAG_ACTIVITY_CLEAR_TASK or
|
|
Intent.FLAG_ACTIVITY_CLEAR_TOP
|
|
)
|
|
}
|
|
activity.startActivity(intent)
|
|
if (finish) {
|
|
activity.finish()
|
|
}
|
|
}
|
|
|
|
@Composable
|
|
fun rememberImeState(): State<Boolean> {
|
|
val imeState = remember { mutableStateOf(false) }
|
|
val view = LocalView.current
|
|
DisposableEffect(view) {
|
|
val listener =
|
|
ViewTreeObserver.OnGlobalLayoutListener {
|
|
val isKeyboardOpen =
|
|
ViewCompat.getRootWindowInsets(view)?.isVisible(WindowInsetsCompat.Type.ime())
|
|
?: true
|
|
imeState.value = isKeyboardOpen
|
|
}
|
|
view.viewTreeObserver.addOnGlobalLayoutListener(listener)
|
|
onDispose { view.viewTreeObserver.removeOnGlobalLayoutListener(listener) }
|
|
}
|
|
return imeState
|
|
}
|
|
|
|
fun getDynamicModuleDisplayName(context: Context, dynamicModuleName: String): String {
|
|
return if (dynamicModuleName == com.navi.common.utils.Constants.HL_DYNAMIC_MODULE_NAME) {
|
|
context.resources.getString(R.string.home_loan_app)
|
|
} else {
|
|
context.resources.getString(R.string.cash_loan_app)
|
|
}
|
|
}
|
|
|
|
fun getHLPrefixScreenName(screenName: String) = "hl_$screenName"
|
|
|
|
fun navigateToCrmHelpScreen(screenName: String, activity: Activity) {
|
|
NaviDeepLinkNavigator.navigate(
|
|
activity = activity,
|
|
ctaData =
|
|
CtaData(
|
|
url = Constants.PRODUCT_HELP_PAGE,
|
|
parameters =
|
|
listOf(LineItem(key = Constants.CRM_HELP_SCREEN_NAME, value = screenName))
|
|
)
|
|
)
|
|
}
|
|
|
|
val naviAppDeserializerGsonBuilder: Gson
|
|
get() =
|
|
GsonBuilder()
|
|
.registerTypeAdapter(GenericWidgetDataInfo::class.java, WidgetDataDeserializer())
|
|
.registerTypeAdapter(WidgetConfig::class.java, WidgetConfigDeserializer())
|
|
.registerTypeAdapter(NaviWidget::class.java, NaviWidgetJsonDeserializer())
|
|
.registerTypeAdapter(BaseInputValidation::class.java, ValidationJsonDeserializer())
|
|
.registerTypeAdapter(ParameterValue::class.java, ParameterValueJsonDeserializer())
|
|
.registerApUiTronDeSerializers()
|
|
.registerTypeAdapter(UiTronData::class.java, CustomHomeWidgetDataDeSerializer())
|
|
.registerTypeAdapter(BaseProperty::class.java, HomeUitronPropertyDeserializer())
|
|
.create()
|
|
|
|
fun naviAppSerializerGsonBuilder(): Gson =
|
|
GsonBuilder()
|
|
.registerTypeAdapter(NaviWidget::class.java, NaviWidgetJsonSerializer())
|
|
.registerTypeAdapter(BaseProperty::class.java, HomeUitronPropertySerializer())
|
|
.registerTypeAdapter(UiTronData::class.java, CustomHomeWidgetDataSerializer())
|
|
.registerTypeAdapter(UiTronAction::class.java, UiTronActionSerializer())
|
|
.registerTypeAdapter(UploadDataConfig::class.java, UiTronUploadDataSerializer())
|
|
.registerTypeAdapter(BaseInputValidation::class.java, UiTronValidationSerializer())
|
|
.registerTypeAdapter(TriggerApiAction::class.java, UiTronTriggerApiActionSerializer())
|
|
.registerTypeAdapter(AnimationSpec::class.java, AnimationSpecSerializer())
|
|
.registerTypeAdapter(PropertyAnimator::class.java, PropertyAnimatorSerializer())
|
|
.registerTypeAdapter(
|
|
VisualTransformationData::class.java,
|
|
VisualTransformationDataSerializer()
|
|
)
|
|
.create()
|
|
|
|
fun buildUrlWithParameters(
|
|
baseUrl: String,
|
|
params: Map<String, String>,
|
|
pathParam: String?
|
|
): String {
|
|
val urlBuilder = StringBuilder(baseUrl)
|
|
if (pathParam.isNotNullAndNotEmpty()) {
|
|
urlBuilder.append(pathParam)
|
|
}
|
|
if (params.isNotEmpty()) {
|
|
urlBuilder.append(QUESTION_MARK)
|
|
urlBuilder.append(params.getEncodedParamsForUrl())
|
|
}
|
|
return urlBuilder.toString()
|
|
}
|