NTP-7460 || Shrihari | Projected Returns for Funds v1 (#13225)

This commit is contained in:
A Shrihari Raju
2024-10-22 23:29:36 +05:30
committed by GitHub
parent 7dbf750a0c
commit ae6e231393
17 changed files with 440 additions and 50 deletions

View File

@@ -30,6 +30,7 @@ import com.navi.amc.common.viewmodel.AmcCommonBottomSheetVM
import com.navi.amc.common.viewmodel.PaymentSharedVM
import com.navi.amc.databinding.FragmentFundBuyingV2Binding
import com.navi.amc.fundbuy.models.AmountPageFooter
import com.navi.amc.fundbuy.models.AmountSimulationData
import com.navi.amc.fundbuy.models.FundBuyData
import com.navi.amc.fundbuy.models.GenericFooter
import com.navi.amc.fundbuy.models.PaymentPostData
@@ -126,6 +127,7 @@ class FundBuyingFragmentV2 : AmcBaseFragment(), WidgetCallback {
private val naviCheckoutViewModel by activityViewModels<NaviCheckoutViewModel>()
private var confinedInvestmentType: String = AmcAnalytics.SIP_AND_LUMPSUM
private var isin: String? = null
private var sipSimulationFragmentData: AmountSimulationData? = null
private lateinit var rewardCalloutWidgetBinding: RewardCalloutWidgetLayoutBinding
private lateinit var timerWithImageWidgetLayoutBinding: TimerWithImageWidgetLayoutBinding
private val genericTimer by lazy { GenericTimer() }
@@ -231,6 +233,16 @@ class FundBuyingFragmentV2 : AmcBaseFragment(), WidgetCallback {
binding.lumpsumPaymentCard.isVisible = false
binding.cutoffBanner.isVisible = false
binding.lumpsumProjection.container.visibility = View.GONE
viewModel.isSipSelected = true
if (
viewModel.isSipFundReturnNegative ||
viewModel.isSipErrorState ||
viewModel.sipType.isNullOrEmpty()
) {
binding.sipProjection.container.visibility = View.GONE
} else {
binding.sipProjection.container.visibility = View.VISIBLE
}
setFooter()
}
@@ -256,11 +268,13 @@ class FundBuyingFragmentV2 : AmcBaseFragment(), WidgetCallback {
} ?: run { binding.lumpsumPaymentCard.isVisible = false }
binding.cutoffBanner.isVisible = true
viewModel.isSipSelected = false
if (viewModel.isFundReturnNegative || viewModel.isAmountErrorState) {
binding.lumpsumProjection.container.visibility = View.GONE
} else {
binding.lumpsumProjection.container.visibility = View.VISIBLE
}
binding.sipProjection.container.visibility = View.GONE
setFooter()
}
@@ -308,6 +322,11 @@ class FundBuyingFragmentV2 : AmcBaseFragment(), WidgetCallback {
binding.lumpsumAmount.toggleSuccessStateVisibility(false)
}
content.fundInvestmentType?.sipSimulationData?.let {
binding.sipAmount.enableSuccessText = false
binding.sipAmount.toggleSuccessStateVisibility(false)
}
viewModel.sipData = content.fundInvestmentType?.sipData
viewModel.lumpsumData = content.fundInvestmentType?.lumpsumData
@@ -375,16 +394,18 @@ class FundBuyingFragmentV2 : AmcBaseFragment(), WidgetCallback {
if (errorState != null && userInput.isNotNullAndNotEmpty()) {
viewModel.isAmountErrorState = false
if (viewModel.isSipSelected == false) {
viewModel.projectedReturn(userInput).apply {
viewModel.projectedText?.let { projectedText ->
projectedText.text = this
binding.lumpsumProjection.projectionTitle
.setSpannableString(projectedText)
slideInFromTop(
binding.lumpsumProjection.container
) {}
viewModel
.projectedReturn(userInput, viewModel.isSipSelected)
.apply {
viewModel.projectedText?.let { projectedText ->
projectedText.text = this
binding.lumpsumProjection.projectionTitle
.setSpannableString(projectedText)
slideInFromTop(
binding.lumpsumProjection.container
) {}
}
}
}
}
} else {
binding.lumpsumProjection.container.visibility = View.GONE
@@ -411,7 +432,8 @@ class FundBuyingFragmentV2 : AmcBaseFragment(), WidgetCallback {
simulationData.simulationText
)
if (viewModel.lumpsumAmount.isNotNullAndNotEmpty()) {
val defaultAmount = viewModel.projectedReturn(viewModel.lumpsumAmount)
val defaultAmount =
viewModel.projectedReturn(viewModel.lumpsumAmount, false)
defaultAmount?.let { amount ->
viewModel.projectedText = simulationData.projectedReturnsText
viewModel.projectedText?.text = amount
@@ -514,12 +536,42 @@ class FundBuyingFragmentV2 : AmcBaseFragment(), WidgetCallback {
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
viewModel.lastSipInteraction = AmcAnalytics.TYPE
binding.sipAmount.getUserInput()?.let { it ->
binding.sipRecommended.setSelectedAmount(it)
binding.sipAmount.getUserInput()?.let { sipUserInput ->
binding.sipRecommended.setSelectedAmount(sipUserInput)
val errorState = binding.sipAmount.getUserInputPostValidation()
if (errorState != null && sipUserInput.isNotNullAndNotEmpty()) {
viewModel.isSipErrorState = false
if (
viewModel.isSipSelected == true &&
viewModel.sipType.isNotNullAndNotEmpty()
) {
viewModel
.projectedReturn(
sipUserInput,
viewModel.isSipSelected,
viewModel.sipType
)
.apply {
viewModel.projectedText?.let { projectedText ->
projectedText.text = this
binding.sipProjection.projectionTitle
.setSpannableString(projectedText)
slideInFromTop(
binding.sipProjection.container
) {}
}
}
}
} else {
binding.sipProjection.container.visibility = View.GONE
snapOut(binding.sipProjection.container) {}
viewModel.isSipErrorState = true
}
(content.fundInvestmentType?.sipData?.getOrNull(1)
as? LabeledTextInputFixedHintWidgetModel)
?.let { sip ->
sip.widgetData?.inputTextFixedHintItemData?.savedText = it
sip.widgetData?.inputTextFixedHintItemData?.savedText =
sipUserInput
}
}
}
@@ -527,6 +579,44 @@ class FundBuyingFragmentV2 : AmcBaseFragment(), WidgetCallback {
override fun afterTextChanged(p0: Editable?) {}
}
)
content.fundInvestmentType?.sipSimulationData?.let { sipSimulationData ->
viewModel.dailySipReturnRate = sipSimulationData.dailySipReturnRate
viewModel.weeklySipReturnRate = sipSimulationData.weeklySipReturnRate
viewModel.monthlySipReturnRate = sipSimulationData.monthlySipReturnRate
viewModel.isSipFundReturnNegative =
when (viewModel.sipType) {
Constant.DAILY -> viewModel.dailySipReturnRate == null
Constant.WEEKLY -> viewModel.weeklySipReturnRate == null
Constant.MONTHLY -> viewModel.monthlySipReturnRate == null
else -> false
}
sipSimulationFragmentData = sipSimulationData
binding.sipProjection.image.showWhenDataIsAvailable(sipSimulationData.iconCode)
binding.sipProjection.title.setSpannableString(sipSimulationData.simulationText)
sipSimulationFragmentData?.let { simulationData ->
if (viewModel.sipAmount.isNotNullAndNotEmpty()) {
viewModel.isSipErrorState = false
val defaultAmount =
viewModel.projectedReturn(
viewModel.sipAmount,
viewModel.isSipSelected,
viewModel.sipType
)
defaultAmount?.let { amount ->
viewModel.projectedText = simulationData.projectedReturnsText
viewModel.projectedText?.text = amount
binding.sipProjection.projectionTitle.setSpannableString(
viewModel.projectedText
)
}
}
}
}
?: run {
viewModel.isSipFundReturnNegative = true
binding.sipAmount.enableSuccessText = true
binding.sipAmount.toggleSuccessStateVisibility(false)
}
content.fundInvestmentType?.sipRecommendedAmount?.let { chipData ->
binding.sipRecommended.setProperties(chipData) { sipRecommended, action ->
val updatedAmount =
@@ -688,6 +778,35 @@ class FundBuyingFragmentV2 : AmcBaseFragment(), WidgetCallback {
)
}
viewModel.selectedSipType.observe(viewLifecycleOwner) {
it.let {
sipSimulationFragmentData?.let { simulationData ->
if (viewModel.sipAmount.isNotNullAndNotEmpty()) {
viewModel.isSipErrorState = false
val defaultAmount =
viewModel.projectedReturn(
viewModel.sipAmount,
viewModel.isSipSelected,
viewModel.sipType
)
defaultAmount?.let { amount ->
viewModel.projectedText = simulationData.projectedReturnsText
viewModel.projectedText?.text = amount
binding.sipProjection.projectionTitle.setSpannableString(
viewModel.projectedText
)
if (
viewModel.isSipSelected == true &&
viewModel.sipType.isNotNullAndNotEmpty()
) {
binding.sipProjection.container.isVisible = true
}
}
}
}
}
}
viewModel.sipDetailsResponse.observe(viewLifecycleOwner) {
hideLoader()
it?.let {
@@ -1046,6 +1165,7 @@ class FundBuyingFragmentV2 : AmcBaseFragment(), WidgetCallback {
bottomSheet.selectedItem.observeNonNull(this) { item ->
binding.sipAmount.visibility = View.VISIBLE
viewModel.sipType = item.id
viewModel.setSelectedSipType(viewModel.sipType)
binding.sipRecommended.isVisible = viewModel.toShowSipRecommended
if (item.id == Constant.MONTHLY) {
viewModel.toHideDate = false
@@ -1527,6 +1647,7 @@ class FundBuyingFragmentV2 : AmcBaseFragment(), WidgetCallback {
sipFrequency?.let { frequency ->
viewModel.sipType = frequency
viewModel.setSelectedSipType(viewModel.sipType)
binding.sipAmount.visibility = View.VISIBLE
binding.sipRecommended.isVisible = viewModel.toShowSipRecommended
val bottomSheetData =

View File

@@ -275,7 +275,9 @@ class FundDetailsFragment : AmcBaseFragment(), FooterInteractionListener {
action = ::setFundReturns,
navigateAction = ::navigate,
apiClickAction = ::pillClickAction,
vmSelectedKey = viewModel.selectedChipId
vmSelectedKey = viewModel.selectedChipId,
setRadioAction = ::setSelectedRadio,
vmSelectedRadio = viewModel.selectedRadio
)
view.tag = "graph"
addView(view)
@@ -430,7 +432,9 @@ class FundDetailsFragment : AmcBaseFragment(), FooterInteractionListener {
action = ::setFundReturns,
navigateAction = ::navigate,
apiClickAction = ::pillClickAction,
vmSelectedKey = viewModel.selectedChipId
vmSelectedKey = viewModel.selectedChipId,
setRadioAction = ::setSelectedRadio,
vmSelectedRadio = viewModel.selectedRadio
)
}
@@ -619,6 +623,10 @@ class FundDetailsFragment : AmcBaseFragment(), FooterInteractionListener {
binding.footer.footerTopNote3.isVisible = true
}
private fun setSelectedRadio(key: String) {
viewModel.selectedRadio = key
}
private fun onTimerRefresh() {
fetchData(genericTimer.isInitialised())
}

View File

@@ -95,12 +95,16 @@ data class FundInvestmentType(
@SerializedName("informationNote") val informationNote: InformationNoteData? = null,
@SerializedName("sipStartDateOffset") val sipStartDateOffset: SipStartDateOffset? = null,
@SerializedName("noteBanner") val noteBanner: NoteBannerData? = null,
@SerializedName("simulationData") val simulationData: AmountSimulationData? = null
@SerializedName("simulationData") val simulationData: AmountSimulationData? = null,
@SerializedName("sipSimulationData") val sipSimulationData: AmountSimulationData? = null
)
data class AmountSimulationData(
@SerializedName("iconCode") val iconCode: String? = null,
@SerializedName("lumpsumReturnRate") val lumpsumReturnRate: Double? = null,
@SerializedName("dailySipReturnRate") val dailySipReturnRate: Double? = null,
@SerializedName("weeklySipReturnRate") val weeklySipReturnRate: Double? = null,
@SerializedName("monthlySipReturnRate") val monthlySipReturnRate: Double? = null,
@SerializedName("backgroundColor") val backgroundColor: String? = null,
@SerializedName("simulationText") val simulationText: TextWithStyle? = null,
@SerializedName("projectedReturnsText") val projectedReturnsText: TextWithStyle? = null

View File

@@ -61,8 +61,18 @@ data class FundDuration(
)
data class ReturnsTooltipData(
@SerializedName("imageUrl") val imageUrl: String? = null,
@SerializedName("title") val title: TextWithStyle? = null
@SerializedName("oneTimeReturns") val oneTimeReturns: ReturnsData? = null,
@SerializedName("sipReturns") val sipReturns: ReturnsData? = null,
@SerializedName("selectedTextColor") val selectedColor: String? = null,
@SerializedName("unselectedTextColor") val unselectedTextColor: String? = null
)
data class ReturnsData(
@SerializedName("key") val key: String? = null,
@SerializedName("title") val title: TextWithStyleVariation? = null,
@SerializedName("imageUrl", alternate = ["iconCode"]) val imageUrl: String? = null,
@SerializedName("returnsInformation") val returnsInformation: TextWithStyle? = null,
@SerializedName("isSelected") val isSelected: Boolean? = null
)
data class XAxisLabelData(

View File

@@ -32,6 +32,7 @@ import com.navi.amc.utils.Constant.WEEKLY
import com.navi.amc.utils.roundOffAmount
import com.navi.amc.utils.updateCheckerResponse
import com.navi.base.model.ActionData
import com.navi.base.utils.orZero
import com.navi.common.utils.EMPTY
import com.navi.common.utils.formatDateIntoPrefixMonthNamesWithYear
import com.navi.common.viewmodel.BaseVM
@@ -75,15 +76,28 @@ class FundBuyV2ViewModel @Inject constructor(private val repository: FundBuyRepo
var sipData: List<NaviWidget>? = null
var lumpsumData: List<NaviWidget>? = null
var lumpSumReturnRate: Double? = null
var dailySipReturnRate: Double? = null
var weeklySipReturnRate: Double? = null
var monthlySipReturnRate: Double? = null
var projectedText: TextWithStyle? = null
var isFundReturnNegative: Boolean = false
var isAmountErrorState: Boolean = false
var isSipFundReturnNegative: Boolean = false
var isSipErrorState: Boolean = false
private val _paymentInitiateData =
MutableLiveData<AdditionalDataAsyncResponse<NextCtaResponse>?>()
val paymentInitiateData: LiveData<AdditionalDataAsyncResponse<NextCtaResponse>?>
get() = _paymentInitiateData
private val _selectedSipType = MutableLiveData<String?>()
val selectedSipType: LiveData<String?>
get() = _selectedSipType
fun setSelectedSipType(sipType: String?) {
_selectedSipType.value = sipType
}
private val gson by lazy { Gson() }
fun getFundBuyScreenData(
@@ -361,10 +375,24 @@ class FundBuyV2ViewModel @Inject constructor(private val repository: FundBuyRepo
return _fundBuyScreenData.value?.content?.isManualVsAutopay.orFalse()
}
fun projectedReturn(userInput: String?): String? {
val returnRate = lumpSumReturnRate
fun projectedReturn(
userInput: String?,
isSipSelected: Boolean? = false,
sipType: String? = null
): String? {
val returnRate =
if (isSipSelected.orFalse()) {
when (sipType) {
WEEKLY -> weeklySipReturnRate
MONTHLY -> monthlySipReturnRate
DAILY -> dailySipReturnRate
else -> null
}
} else {
lumpSumReturnRate
}
if (returnRate != null && userInput != null) {
return roundOffAmount(userInput.toDouble() * returnRate)
return roundOffAmount(userInput.toDouble().orZero() * returnRate)
}
return null
}

View File

@@ -48,6 +48,7 @@ class FundDetailViewModel @Inject constructor(private val repository: FundDetail
val chipIdToGraphDataMap = mutableMapOf<String, FundGraphData>()
var selectedChipId: String? = null
var fundName: String? = null
var selectedRadio: String? = null
fun getFundScreenData(isin: String) {
viewModelScope.launch {

View File

@@ -44,14 +44,17 @@ import com.navi.amc.fundbuy.models.FundDuration
import com.navi.amc.fundbuy.models.FundGraphData
import com.navi.amc.fundbuy.models.FundGraphDetails
import com.navi.amc.fundbuy.models.FundReturn
import com.navi.amc.fundbuy.models.ReturnsData
import com.navi.amc.utils.ColorUtils
import com.navi.amc.utils.ColorUtils.FUND_GRAPH_BG_END_GRADIENT_COLOR
import com.navi.amc.utils.ColorUtils.FUND_GRAPH_BG_START_GRADIENT_COLOR
import com.navi.amc.utils.ColorUtils.FUND_GRAPH_CHIP_SELECTED_COLOR
import com.navi.amc.utils.Constant
import com.navi.base.model.ActionData
import com.navi.base.utils.orFalse
import com.navi.base.utils.orZero
import com.navi.common.animation.fadeIn
import com.navi.design.textview.model.TextWithStyle
import com.navi.design.utils.CornerRadius
import com.navi.design.utils.dpToPxInInt
import com.navi.design.utils.getNaviDrawable
@@ -72,11 +75,27 @@ class FundGraphView(context: Context, attributeSet: AttributeSet? = null) :
private var isInvestmentDetailsUpdated: Boolean = false
private var isGraphPillUpdated: Boolean = false
private var selectedKey: String? = null
private var selectedRadio: String? = null
private var setRadioAction: ((String) -> Unit)? = null
private var fundDurationData: FundDuration? = null
private var selectedId: Int = 0
init {
val inflater = LayoutInflater.from(context)
binding = DataBindingUtil.inflate(inflater, R.layout.fund_graph_layout, this, true)
layoutParams = LayoutParams(MATCH_PARENT, WRAP_CONTENT)
binding.chipTooltipContent.radioGroup.setOnCheckedChangeListener { group, checkedId ->
when (checkedId) {
R.id.radio_option_one_time -> {
selectedRadio = Constant.ONE_TIME
}
R.id.radio_option_sip -> {
selectedRadio = Constant.SIP
}
}
updateSelectedTooltip(fundDurationData, selectedId)
}
}
fun setProperties(
@@ -86,9 +105,13 @@ class FundGraphView(context: Context, attributeSet: AttributeSet? = null) :
action: ((FundReturn) -> Unit)? = null,
navigateAction: ((ActionData) -> Unit)? = null,
apiClickAction: ((String?, Boolean?) -> Unit)? = null,
vmSelectedKey: String? = null
vmSelectedKey: String? = null,
setRadioAction: ((String) -> Unit)? = null,
vmSelectedRadio: String? = null
) {
this.apiClickAction = apiClickAction
this.setRadioAction = setRadioAction
selectedRadio = vmSelectedRadio
if (isGraphPillUpdated.not()) {
setFundGraphPillsData(data, vmSelectedKey)
}
@@ -456,31 +479,92 @@ class FundGraphView(context: Context, attributeSet: AttributeSet? = null) :
}
private fun updateSelectedTooltip(childData: FundDuration?, childId: Int) {
childData?.returnsTooltip?.let { tooltipData ->
val triangle = binding.triangles.findViewById<ImageView>(childId)
binding.triangles.visibility = View.VISIBLE
triangle.visibility = View.VISIBLE
fadeIn(binding.chipTooltipContent.root) {}
binding.chipTooltipContent.tooltipImage.showWhenDataIsAvailable(tooltipData.imageUrl)
binding.chipTooltipContent.title.setSpannableString(tooltipData.title)
}
?: run {
val triangle = binding.triangles.findViewById<ImageView>(childId)
TransitionManager.beginDelayedTransition(
binding.root as ViewGroup,
Fade().apply { duration = FADE_OUT_DURATION }
)
triangle.visibility = View.GONE
binding.triangles.visibility = View.GONE
binding.chipTooltipContent.root.visibility = View.GONE
binding.chipTooltipContent.radioOptionOneTime.setSpannableString(
childData?.returnsTooltip?.oneTimeReturns?.title
)
binding.chipTooltipContent.radioOptionSip.setSpannableString(
childData?.returnsTooltip?.sipReturns?.title
)
binding.chipTooltipContent.divider.visibility = View.VISIBLE
fundDurationData = childData
selectedId = childId
setRadioAction?.invoke(selectedRadio.orEmpty())
when (selectedRadio) {
Constant.ONE_TIME -> {
childData?.returnsTooltip?.oneTimeReturns?.let { tooltipData ->
binding.chipTooltipContent.radioOptionSip.setSpannableString(
childData.returnsTooltip.sipReturns?.title
)
binding.chipTooltipContent.radioOptionOneTime.setSpannableString(
textData =
TextWithStyle(
text = childData.returnsTooltip.oneTimeReturns.title?.text,
style =
childData.returnsTooltip.oneTimeReturns.title
?.styleVariations
?.get("selected")
)
)
binding.chipTooltipContent.radioOptionOneTime.isChecked = true
setTooltipData(tooltipData, childId)
} ?: run { fadeOutTooltip(childId) }
}
Constant.SIP -> {
childData?.returnsTooltip?.sipReturns?.let { tooltipData ->
binding.chipTooltipContent.radioOptionOneTime.setSpannableString(
childData.returnsTooltip.oneTimeReturns?.title
)
binding.chipTooltipContent.radioOptionSip.setSpannableString(
textData =
TextWithStyle(
text = childData.returnsTooltip.sipReturns.title?.text,
style =
childData.returnsTooltip.sipReturns.title
?.styleVariations
?.get("selected")
)
)
binding.chipTooltipContent.radioOptionSip.isChecked = true
setTooltipData(tooltipData, childId)
} ?: run { fadeOutTooltip(childId) }
}
else -> {
selectedRadio =
childData?.returnsTooltip?.oneTimeReturns?.isSelected?.let {
if (it) Constant.ONE_TIME else Constant.SIP
} ?: Constant.SIP
updateSelectedTooltip(childData, childId)
}
}
}
private fun setTooltipData(toolTipData: ReturnsData, childId: Int) {
val triangle = binding.triangles.findViewById<ImageView>(childId)
binding.triangles.visibility = View.VISIBLE
triangle.visibility = View.VISIBLE
fadeIn(binding.chipTooltipContent.root) {}
binding.chipTooltipContent.tooltipImage.showWhenDataIsAvailable(toolTipData.imageUrl)
binding.chipTooltipContent.title.setSpannableString(toolTipData.returnsInformation)
}
private fun fadeOutTooltip(childId: Int) {
val triangle = binding.triangles.findViewById<ImageView>(childId)
TransitionManager.beginDelayedTransition(
binding.root as ViewGroup,
Fade().apply { duration = FADE_OUT_DURATION }
)
triangle.visibility = View.GONE
binding.triangles.visibility = View.GONE
binding.chipTooltipContent.root.visibility = View.GONE
}
companion object {
const val TAG = "FundGraphView"
const val TRIANGLE_WIDTH = 20
const val TRIANGLE_HEIGHT = 12
const val TRIANGLE_HEIGHT = 10
const val TRIANGLE_MARGIN_START = 16
const val TRIANGLE_MARGIN_TOP = 8
const val TRIANGLE_MARGIN_END = 16

View File

@@ -27,6 +27,8 @@ object ColorUtils {
const val FUND_GRAPH_BG_START_GRADIENT_COLOR = "#64FFFCEC"
const val FUND_GRAPH_BG_END_GRADIENT_COLOR = "#FFFFFF"
const val FUND_GRAPH_CHIP_SELECTED_COLOR = "#1F002A"
const val RADIO_SELECTED_COLOR = "#191919"
const val RADIO_UNSELECTED_COLOR = "#6B6B6B"
fun getPurpleRoundedDrawable(context: Context) =
getNaviDrawable(

View File

@@ -42,6 +42,7 @@ import com.navi.naviwidgets.widgets.NaviWidgetJsonDeserializer
import java.lang.reflect.Type
import java.net.URI
import java.text.DecimalFormat
import java.text.NumberFormat
import java.text.SimpleDateFormat
import java.util.TimeZone
import kotlin.math.floor
@@ -207,11 +208,13 @@ fun getFundGraphItemCacheKey(key: String, fundName: String): String {
fun roundOffAmount(value: Double): String {
// function to return amount in K, L, Cr if greater than 10K and rounded up to 2 decimal places
val df = DecimalFormat("#.##")
val nf = NumberFormat.getInstance().apply { maximumFractionDigits = 0 }
return RUPEE_SYMBOL +
when {
value >= 1_00_00_000 -> df.format(floor(value / 1_00_00_000 * 100) / 100) + " Cr"
value >= 1_00_000 -> df.format(floor(value / 1_00_000 * 100) / 100) + " L"
value >= 10_000 -> df.format(floor(value / 1_000 * 100) / 100) + " K"
value >= 1_000 -> nf.format(value)
else -> df.format(floor(value * 100) / 100.0f)
}
}

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~
~ * Copyright © 2022-2023 by Navi Technologies Limited
~ * All rights reserved. Strictly confidential
~
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/ic_radio_button_default" android:state_checked="false" />
<item android:drawable="@drawable/ic_radio_button_selected" android:state_checked="true" />
<item android:drawable="@drawable/ic_radio_button_default" />
</selector>

View File

@@ -0,0 +1,23 @@
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16"
>
<group>
<clip-path
android:pathData="M8 0C12.4183 0 16 3.58172 16 8C16 12.4183 12.4183 16 8 16C3.58172 16 0 12.4183 0 8C0 3.58172 3.58172 0 8 0Z"
/>
<path
android:pathData="M0 0V16H16V0"
android:fillColor="#FFFFFF"
/>
<path
android:pathData="M8 0C12.4183 0 16 3.58172 16 8C16 12.4183 12.4183 16 8 16C3.58172 16 0 12.4183 0 8C0 3.58172 3.58172 0 8 0Z"
android:strokeWidth="1.34"
android:strokeColor="#EBEBEB"
/>
</group>
</vector>

View File

@@ -0,0 +1,24 @@
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16"
>
<group>
<clip-path
android:pathData="M8 0C12.4183 0 16 3.58172 16 8C16 12.4183 12.4183 16 8 16C3.58172 16 0 12.4183 0 8C0 3.58172 3.58172 0 8 0Z"
/>
<path
android:pathData="M8 0C12.4183 0 16 3.58172 16 8C16 12.4183 12.4183 16 8 16C3.58172 16 0 12.4183 0 8C0 3.58172 3.58172 0 8 0Z"
android:strokeWidth="2.69"
android:strokeColor="#1F002A"
/>
<path
android:strokeWidth="1"
android:pathData="M11.5,8C11.5,9.933 9.933,11.5 8,11.5C6.067,11.5 4.5,9.933 4.5,8C4.5,6.067 6.067,4.5 8,4.5C9.933,4.5 11.5,6.067 11.5,8Z"
android:fillColor="#1F002A"
android:strokeColor="#1F002A"/>
</group>
</vector>

View File

@@ -126,12 +126,12 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_16"
android:layout_marginTop="@dimen/dp_24"
android:layout_marginTop="@dimen/dp_130"
android:layout_marginEnd="@dimen/dp_16"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/sip_amount" />
app:layout_constraintTop_toTopOf="@id/sip_amount" />
<androidx.cardview.widget.CardView
android:id="@+id/lumpsum_payment_card"
@@ -286,6 +286,20 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/sip_frequency" />
<include
android:id="@+id/sip_projection"
layout="@layout/amc_amount_projection_fundbuy_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:paddingTop="@dimen/_4dp"
android:layout_marginTop="-4dp"
android:elevation="-2dp"
android:layout_marginHorizontal="@dimen/_16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/sip_amount" />
<com.navi.naviwidgets.widgets.labeledinputsearch.ui.LabeledTextSearchInputWidget
android:id="@+id/date"
android:layout_width="match_parent"

View File

@@ -214,10 +214,10 @@
android:layout_height="wrap_content"
android:translationZ="8dp"
android:visibility="gone"
android:layout_marginTop="-8dp"
android:layout_marginTop="@dimen/dp_57"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/chip_group" />
app:layout_constraintTop_toTopOf="@id/chip_group" />
<com.navi.amc.common.view.FundInvestmentDetailsView

View File

@@ -18,11 +18,56 @@
android:background="@drawable/box_shadow_bottom_4"
android:layout_height="wrap_content">
<RadioGroup
android:id="@+id/radio_group"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_width="match_parent"
android:weightSum="@integer/integer_1"
android:layout_height="wrap_content"
android:orientation="horizontal">
<RadioButton
android:id="@+id/radio_option_one_time"
tools:text="One-time"
android:button="@null"
android:drawableStart="@drawable/amc_radio_button_selector"
android:drawablePadding="@dimen/_8dp"
android:background="@null"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<RadioButton
android:layout_marginStart="@dimen/dp_31"
android:id="@+id/radio_option_sip"
tools:text="Monthly SIP"
android:button="@null"
android:drawableStart="@drawable/amc_radio_button_selector"
android:drawablePadding="@dimen/_8dp"
android:background="@null"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</RadioGroup>
<View
android:id="@+id/divider"
android:layout_width="@dimen/dp_0"
android:layout_height="@dimen/_20dp"
android:background="@drawable/horizontal_straight_line_ebebeb"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/radio_group"
tools:visibility="visible" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/tooltip_image"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginStart="@dimen/_16dp"
app:layout_constraintTop_toBottomOf="@id/divider"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/title"
android:layout_width="@dimen/_44dp"
android:layout_height="@dimen/_44dp"/>
@@ -31,10 +76,9 @@
android:layout_width="@dimen/_0dp"
android:layout_height="wrap_content"
android:lineSpacingExtra="@dimen/_3dp"
android:layout_marginStart="@dimen/_12dp"
app:layout_constraintStart_toEndOf="@id/tooltip_image"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/tooltip_image"
app:layout_constraintTop_toBottomOf="@id/divider"
app:layout_constraintBottom_toBottomOf="parent"
tools:text="About SIPS" />

View File

@@ -67,6 +67,7 @@
<dimen name="dp_52">52dp</dimen>
<dimen name="dp_54">54dp</dimen>
<dimen name="dp_56">56dp</dimen>
<dimen name="dp_57">57dp</dimen>
<dimen name="dp_58">58dp</dimen>
<dimen name="dp_60">60dp</dimen>
<dimen name="dp_62">62dp</dimen>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="line">
<stroke
android:width="1dp"
android:color="#EBEBEB"/>
</shape>