How to Build SIP Calculator Android App using MVP Architecture?
SIP, the Systematic Investment Plan. One of the methods to invest in Mutual Funds is weekly, monthly quarterly, or half-yearly. The SIP calculator is the tool to get an idea for investors about their investment returns. However, the returns of mutual funds vary on various factors. For example, the SIP calculator does not calculate the Absolute returns because some mutual funds have exit load and expense ratio charged. So, it only calculates estimated returns and provides the result of maturity value. This article its been discussed, implementing the SIP calculator in Android with robust MVP architecture. Have a look at the following to get an idea of the end product.
How Does SIP return Calculator Helps?
SIPs provide very lucrative returns when compared to lumpsum investments in mutual funds. The SIP calculator helps investors to make investment plans for the long term as it provides the following:
- It determines the total amount invested over time.
- Tells about estimated returns over the expected rate of return.
- Also calculates the maturity value, which is estimated returns + total invested amount.
Note: Estimated returns are simply the maturity value β total invested amount.
The formula to calculate the SIP returns is simple.
m = p * ( { ( 1 + i ) ^ n β 1 } / i ) * ( i + 1 )
m -> Maturity Value (Estimated Return + Total Amount Invested).
p -> principal amount (to be invested monthly).
i -> period interest rate.
n -> number of payments made.
Benefits one get from this calculator
- Based on the estimated return, one can plan investments for the long term in mutual funds.
- It provides accurate estimations.
- As per your financial needs, it helps to shape your portfolio by providing accuracy referring to your researched mutual fund past performance.
Before going to implementation, some prerequisites
- MVP (Model View Presenter) Architecture Pattern in Android with Example β to know how MVP architecture works in android with an example.
- Material Design Components Sliders in Android β to know how one can use the sliders in Android.
- How to add a Pie Chart into an Android Application β to know how to implement the pie charts in android.
Steps to implement the SIP Calculator in Android
Step 1: Create a New Project
To create a new project in Android Studio please refer to How to Create/Start a New Project in Android Studio. Note that select Kotlin as the programming language.
Step 2: Working with the activity_main.xml file
The main layout of the application contains 3 edit texts and associated sliders with them so that users can slide and make changes in the edit text instead of typing. One Calculate button which upon pressing it calculates according to the formula mentioned. One is a pie chart and this pie chart got two slices, one is for the invested amount over the period and another slice is estimated returns the investment generated over the expected rate of return and selected tenure. To implement the same invoke the following code inside the activity_main.xml file.
XML
<? xml version = "1.0" encoding = "utf-8" ?> < ScrollView xmlns:android = "http://schemas.android.com/apk/res/android" xmlns:app = "http://schemas.android.com/apk/res-auto" xmlns:tools = "http://schemas.android.com/tools" android:layout_width = "match_parent" android:layout_height = "match_parent" android:clipToPadding = "false" tools:context = ".View.SipCalculatorView" tools:ignore = "HardcodedText" > < androidx.constraintlayout.widget.ConstraintLayout android:layout_width = "match_parent" android:layout_height = "wrap_content" > < androidx.cardview.widget.CardView android:id = "@+id/monthlyInvestmentAmountCardView" android:layout_width = "match_parent" android:layout_height = "wrap_content" android:layout_marginStart = "16dp" android:layout_marginTop = "16dp" android:layout_marginEnd = "16dp" app:cardCornerRadius = "8dp" app:cardElevation = "4dp" app:cardMaxElevation = "6dp" app:cardPreventCornerOverlap = "true" app:layout_constraintEnd_toEndOf = "parent" app:layout_constraintStart_toStartOf = "parent" app:layout_constraintTop_toTopOf = "parent" > < androidx.constraintlayout.widget.ConstraintLayout android:layout_width = "match_parent" android:layout_height = "match_parent" android:padding = "12dp" > < com.google.android.material.textfield.TextInputLayout android:id = "@+id/monthlyInvestmentAmountTextInputLayout" android:layout_width = "match_parent" android:layout_height = "wrap_content" android:hint = "Monthly Investment Amount (in Rs.)" app:layout_constraintTop_toTopOf = "parent" tools:layout_editor_absoluteX = "8dp" > < com.google.android.material.textfield.TextInputEditText android:id = "@+id/monthlyInvestmentAmountTextInputEditText" android:layout_width = "match_parent" android:layout_height = "wrap_content" android:inputType = "number" /> </ com.google.android.material.textfield.TextInputLayout > < com.google.android.material.slider.Slider android:id = "@+id/monthlyInvestmentAmountSlider" android:layout_width = "match_parent" android:layout_height = "wrap_content" android:layout_marginTop = "8dp" android:stepSize = "5000" android:valueFrom = "5000" android:valueTo = "50000" app:layout_constraintTop_toBottomOf = "@id/monthlyInvestmentAmountTextInputLayout" tools:layout_editor_absoluteX = "8dp" /> </ androidx.constraintlayout.widget.ConstraintLayout > </ androidx.cardview.widget.CardView > < androidx.cardview.widget.CardView android:id = "@+id/expectedReturnRateCardView" android:layout_width = "match_parent" android:layout_height = "wrap_content" android:layout_marginStart = "16dp" android:layout_marginTop = "16dp" android:layout_marginEnd = "16dp" app:cardCornerRadius = "8dp" app:cardElevation = "4dp" app:cardMaxElevation = "6dp" app:cardPreventCornerOverlap = "true" app:layout_constraintEnd_toEndOf = "parent" app:layout_constraintStart_toStartOf = "parent" app:layout_constraintTop_toBottomOf = "@id/monthlyInvestmentAmountCardView" > < androidx.constraintlayout.widget.ConstraintLayout android:layout_width = "match_parent" android:layout_height = "match_parent" android:padding = "12dp" > < com.google.android.material.textfield.TextInputLayout android:id = "@+id/expectedReturnRateTextInputLayout" android:layout_width = "match_parent" android:layout_height = "wrap_content" android:hint = "Expected Rate of Return (in %)" app:layout_constraintEnd_toEndOf = "parent" app:layout_constraintStart_toStartOf = "parent" app:layout_constraintTop_toTopOf = "parent" > < com.google.android.material.textfield.TextInputEditText android:id = "@+id/expectedReturnRateTextInputEditText" android:layout_width = "match_parent" android:layout_height = "wrap_content" android:inputType = "number" /> </ com.google.android.material.textfield.TextInputLayout > < com.google.android.material.slider.Slider android:id = "@+id/expectedReturnRateSlider" android:layout_width = "match_parent" android:layout_height = "wrap_content" android:layout_marginTop = "8dp" android:stepSize = "1" android:valueFrom = "5" android:valueTo = "30" app:layout_constraintTop_toBottomOf = "@id/expectedReturnRateTextInputLayout" tools:layout_editor_absoluteX = "12dp" /> </ androidx.constraintlayout.widget.ConstraintLayout > </ androidx.cardview.widget.CardView > < androidx.cardview.widget.CardView android:id = "@+id/investmentTimePeriodCardView" android:layout_width = "match_parent" android:layout_height = "wrap_content" android:layout_marginStart = "16dp" android:layout_marginTop = "16dp" android:layout_marginEnd = "16dp" app:cardCornerRadius = "8dp" app:cardElevation = "4dp" app:cardMaxElevation = "6dp" app:cardPreventCornerOverlap = "true" app:layout_constraintEnd_toEndOf = "parent" app:layout_constraintStart_toStartOf = "parent" app:layout_constraintTop_toBottomOf = "@+id/expectedReturnRateCardView" > < androidx.constraintlayout.widget.ConstraintLayout android:layout_width = "match_parent" android:layout_height = "match_parent" android:padding = "12dp" > < com.google.android.material.textfield.TextInputLayout android:id = "@+id/investmentTimePeriodTextInputLayout" android:layout_width = "match_parent" android:layout_height = "wrap_content" android:hint = "Investment Time Period (in Years)" app:layout_constraintEnd_toEndOf = "parent" app:layout_constraintStart_toStartOf = "parent" app:layout_constraintTop_toTopOf = "parent" > < com.google.android.material.textfield.TextInputEditText android:id = "@+id/investmentTimePeriodTextInputEditText" android:layout_width = "match_parent" android:layout_height = "wrap_content" android:inputType = "number" /> </ com.google.android.material.textfield.TextInputLayout > < com.google.android.material.slider.Slider android:id = "@+id/investmentTimePeriodSlider" android:layout_width = "match_parent" android:layout_height = "wrap_content" android:layout_marginTop = "8dp" android:stepSize = "1" android:valueFrom = "5" android:valueTo = "30" app:layout_constraintTop_toBottomOf = "@id/investmentTimePeriodTextInputLayout" tools:layout_editor_absoluteX = "12dp" /> </ androidx.constraintlayout.widget.ConstraintLayout > </ androidx.cardview.widget.CardView > < com.google.android.material.button.MaterialButton android:id = "@+id/sipCalculateResultButton" android:layout_width = "match_parent" android:layout_height = "wrap_content" android:layout_marginStart = "16dp" android:layout_marginTop = "16dp" android:layout_marginEnd = "16dp" android:text = "CALCULATE" app:layout_constraintEnd_toEndOf = "parent" app:layout_constraintStart_toStartOf = "parent" app:layout_constraintTop_toBottomOf = "@id/investmentTimePeriodCardView" /> < androidx.cardview.widget.CardView android:id = "@+id/sipCalculationResultCardView" android:layout_width = "match_parent" android:layout_height = "wrap_content" android:layout_margin = "16dp" app:cardCornerRadius = "8dp" app:cardElevation = "4dp" app:cardMaxElevation = "6dp" app:cardPreventCornerOverlap = "true" app:layout_constraintBottom_toBottomOf = "parent" app:layout_constraintEnd_toEndOf = "parent" app:layout_constraintStart_toStartOf = "parent" app:layout_constraintTop_toBottomOf = "@+id/sipCalculateResultButton" > < androidx.constraintlayout.widget.ConstraintLayout android:layout_width = "match_parent" android:layout_height = "match_parent" android:padding = "16dp" > < View android:id = "@+id/view" android:layout_width = "24dp" android:layout_height = "24dp" android:background = "@color/green_200" app:layout_constraintStart_toStartOf = "parent" app:layout_constraintTop_toTopOf = "@+id/totalInvestedAmountMaterialHeading" /> < com.google.android.material.textview.MaterialTextView android:id = "@+id/totalInvestedAmountMaterialHeading" style = "@style/TextAppearance.MdcTypographyStyles.Subtitle1" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_marginStart = "8dp" android:text = "Invested Amount" app:layout_constraintStart_toEndOf = "@+id/view" app:layout_constraintTop_toTopOf = "parent" /> < com.google.android.material.textview.MaterialTextView android:id = "@+id/totalInvestedAmountMaterialTextView" style = "@style/TextAppearance.MdcTypographyStyles.Headline6" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_marginTop = "2dp" app:layout_constraintStart_toStartOf = "@+id/totalInvestedAmountMaterialHeading" app:layout_constraintTop_toBottomOf = "@+id/totalInvestedAmountMaterialHeading" tools:text = "10000" /> < View android:id = "@+id/view2" android:layout_width = "24dp" android:layout_height = "24dp" android:background = "@color/blue_200" app:layout_constraintStart_toStartOf = "parent" app:layout_constraintTop_toTopOf = "@+id/estimatedReturnsMaterialHeading" /> < com.google.android.material.textview.MaterialTextView android:id = "@+id/estimatedReturnsMaterialHeading" style = "@style/TextAppearance.MdcTypographyStyles.Subtitle1" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_marginStart = "8dp" android:layout_marginTop = "12dp" android:text = "Estimated Returns" app:layout_constraintStart_toEndOf = "@+id/view2" app:layout_constraintTop_toBottomOf = "@+id/totalInvestedAmountMaterialTextView" /> < com.google.android.material.textview.MaterialTextView android:id = "@+id/estimatedReturnsMaterialTextView" style = "@style/TextAppearance.MdcTypographyStyles.Headline6" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_marginTop = "2dp" app:layout_constraintStart_toStartOf = "@+id/estimatedReturnsMaterialHeading" app:layout_constraintTop_toBottomOf = "@+id/estimatedReturnsMaterialHeading" tools:text = "25000" /> < com.google.android.material.textview.MaterialTextView android:id = "@+id/totalAmountMaterialHeading" style = "@style/TextAppearance.MdcTypographyStyles.Subtitle1" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_marginTop = "12dp" android:text = "Total Amount" app:layout_constraintStart_toStartOf = "parent" app:layout_constraintTop_toBottomOf = "@+id/estimatedReturnsMaterialTextView" /> < com.google.android.material.textview.MaterialTextView android:id = "@+id/totalAmountMaterialTextView" style = "@style/TextAppearance.MdcTypographyStyles.Headline6" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_marginTop = "2dp" app:layout_constraintStart_toStartOf = "@+id/totalAmountMaterialHeading" app:layout_constraintTop_toBottomOf = "@+id/totalAmountMaterialHeading" tools:text = "35000" /> < org.eazegraph.lib.charts.PieChart android:id = "@+id/sipResultPieChart" android:layout_width = "128dp" android:layout_height = "128dp" app:layout_constraintBottom_toBottomOf = "parent" app:layout_constraintEnd_toEndOf = "parent" app:layout_constraintTop_toTopOf = "parent" /> </ androidx.constraintlayout.widget.ConstraintLayout > </ androidx.cardview.widget.CardView > </ androidx.constraintlayout.widget.ConstraintLayout > </ ScrollView > |
However following is optional, the application is branded with the Roboto type system suggested by Google Material Design. Include the following code inside the themes.xml file.
XML
< resources xmlns:tools = "http://schemas.android.com/tools" > <!-- Base application theme. --> < style name = "Theme.GFGSIPCalculator" parent = "Theme.MaterialComponents.DayNight.DarkActionBar" > <!-- Primary brand color. --> < item name = "colorPrimary" >@color/green_500</ item > < item name = "colorPrimaryVariant" >@color/green_700</ item > < item name = "colorOnPrimary" >@color/white</ item > <!-- Secondary brand color. --> < item name = "colorSecondary" >@color/teal_200</ item > < item name = "colorSecondaryVariant" >@color/teal_700</ item > < item name = "colorOnSecondary" >@color/black</ item > <!-- Status bar color. --> < item name = "android:statusBarColor" tools:targetApi = "l" >?attr/colorPrimaryVariant</ item > <!-- Customize your theme here. --> </ style > < style name = "TextAppearance.MdcTypographyStyles.Headline1" parent = "TextAppearance.MaterialComponents.Headline1" > < item name = "fontFamily" >@font/roboto_light</ item > < item name = "android:fontFamily" >@font/roboto_light</ item > < item name = "android:textSize" >96sp</ item > </ style > < style name = "TextAppearance.MdcTypographyStyles.Headline2" parent = "TextAppearance.MaterialComponents.Headline2" > < item name = "fontFamily" >@font/roboto_light</ item > < item name = "android:fontFamily" >@font/roboto_light</ item > < item name = "android:textSize" >60sp</ item > </ style > < style name = "TextAppearance.MdcTypographyStyles.Headline3" parent = "TextAppearance.MaterialComponents.Headline3" > < item name = "fontFamily" >@font/roboto_regular</ item > < item name = "android:fontFamily" >@font/roboto_regular</ item > < item name = "android:textSize" >48sp</ item > </ style > < style name = "TextAppearance.MdcTypographyStyles.Headline4" parent = "TextAppearance.MaterialComponents.Headline4" > < item name = "fontFamily" >@font/roboto_regular</ item > < item name = "android:fontFamily" >@font/roboto_regular</ item > < item name = "android:textSize" >34sp</ item > </ style > < style name = "TextAppearance.MdcTypographyStyles.Headline5" parent = "TextAppearance.MaterialComponents.Headline5" > < item name = "fontFamily" >@font/roboto_regular</ item > < item name = "android:fontFamily" >@font/roboto_regular</ item > < item name = "android:textSize" >24sp</ item > </ style > < style name = "TextAppearance.MdcTypographyStyles.Headline6" parent = "TextAppearance.MaterialComponents.Headline6" > < item name = "fontFamily" >@font/roboto_medium</ item > < item name = "android:fontFamily" >@font/roboto_medium</ item > < item name = "android:textSize" >20sp</ item > </ style > < style name = "TextAppearance.MdcTypographyStyles.Subtitle1" parent = "TextAppearance.MaterialComponents.Subtitle1" > < item name = "fontFamily" >@font/roboto_regular</ item > < item name = "android:fontFamily" >@font/roboto_regular</ item > < item name = "android:textSize" >16sp</ item > </ style > < style name = "TextAppearance.MdcTypographyStyles.Subtitle2" parent = "TextAppearance.MaterialComponents.Subtitle2" > < item name = "fontFamily" >@font/roboto_medium</ item > < item name = "android:fontFamily" >@font/roboto_medium</ item > < item name = "android:textSize" >14sp</ item > </ style > < style name = "TextAppearance.MdcTypographyStyles.Body1" parent = "TextAppearance.MaterialComponents.Body1" > < item name = "fontFamily" >@font/roboto_regular</ item > < item name = "android:fontFamily" >@font/roboto_regular</ item > < item name = "android:textSize" >16sp</ item > </ style > < style name = "TextAppearance.MdcTypographyStyles.Body2" parent = "TextAppearance.MaterialComponents.Body2" > < item name = "fontFamily" >@font/roboto_regular</ item > < item name = "android:fontFamily" >@font/roboto_regular</ item > < item name = "android:textSize" >14sp</ item > </ style > < style name = "TextAppearance.MdcTypographyStyles.Button" parent = "TextAppearance.MaterialComponents.Button" > < item name = "fontFamily" >@font/roboto_regular</ item > < item name = "android:fontFamily" >@font/roboto_regular</ item > < item name = "android:textSize" >14sp</ item > </ style > < style name = "TextAppearance.MdcTypographyStyles.Caption" parent = "TextAppearance.MaterialComponents.Caption" > < item name = "fontFamily" >@font/roboto_regular</ item > < item name = "android:fontFamily" >@font/roboto_regular</ item > < item name = "android:textSize" >12sp</ item > </ style > < style name = "TextAppearance.MdcTypographyStyles.Overline" parent = "TextAppearance.MaterialComponents.Overline" > < item name = "fontFamily" >@font/roboto_regular</ item > < item name = "android:fontFamily" >@font/roboto_regular</ item > < item name = "android:textSize" >10sp</ item > </ style > </ resources > |
Step 3: Working with the Architecture
As the architecture components required for this application are small yet easy to maintain and document and scale the application. So the following image represents that one should create architecture components classes and associated interface as the interface here is called a contract, in the MVP architecture. Create a package for each component of the architecture.
Step 4: Working with all the interfaces(contracts) of the architecture
SipCalculatorModelInterface:
Kotlin
interface SipCalculatorModelInterface { fun getTotalInvestedAmount(): Long fun getEstimatedReturns(): Long fun getTotalValue(): Long } |
SipCalculatorPresenterInterface:
Kotlin
interface SipCalculatorPresenterInterface { fun forCalculation( monthlyInvestmentAmount: String, expectedReturnRate: String, investmentTimePeriod: String ) } |
SipCalculatorViewInterface:
Kotlin
interface SipCalculatorViewInterface { fun onCalculationResult( totalInvestedAmount: String, estimatedReturns: String, totalValue: String ) } |
Step 5: Working with SipCalculatorModel.kt class
This class implements the SipCalculatorModelInterface. and this contains the main logic that is calculating all the results. Comments are added for better understanding.
Kotlin
class SipCalculatorModel( monthlyInvestmentAmount: String, expectedReturnRate: String, investmentTimePeriod: String ) : SipCalculatorModelInterface { val TAG = SipCalculatorModel:: class .java.simpleName // convert all the inputs to integer. private var monthlyInvestmentAmountInt: Int = monthlyInvestmentAmount.toInt() private var expectedReturnRateInt: Int = expectedReturnRate.toInt() private var investmentTimePeriodInt: Int = investmentTimePeriod.toInt() * 12 // total investment is considered here is according to monthly investment plans override fun getTotalInvestedAmount(): Long { return (monthlyInvestmentAmountInt * investmentTimePeriodInt).toLong() } // estimated returns = maturity value - total investment amount override fun getEstimatedReturns(): Long { return getTotalValue() - getTotalInvestedAmount() } // calculate the maturity value according to the formula override fun getTotalValue(): Long { val periodicInterest: Float = ((expectedReturnRateInt.toFloat() / 12 ) / 100 ) return (monthlyInvestmentAmountInt * (((Math.pow( ( 1 + periodicInterest).toDouble(), investmentTimePeriodInt.toDouble() ) - 1 ) / periodicInterest) * ( 1 + periodicInterest))) .toLong() } } |
Step 6: Working with SipCalculatorPresenter.kt class
This class implements the SipCalculatorPresenterInterface, this simply acts between the SipCalculatorModel and SipCalculatorView. Invoke the following code inside the SipCalculatorPresenter.kt class. Comments are added for better understanding.
Kotlin
import com.adityamshidlyali.gfgsipcalculator.Model.SipCalculatorModel import com.adityamshidlyali.gfgsipcalculator.View.SipCalculatorViewInterface class SipCalculatorPresenter( private val sipCalculatorViewInterface: SipCalculatorViewInterface ) : SipCalculatorPresenterInterface { override fun forCalculation( monthlyInvestmentAmount: String, expectedReturnRate: String, investmentTimePeriod: String ) { // create instance of the sip model and calculate all the results. val sipModel = SipCalculatorModel( monthlyInvestmentAmount, expectedReturnRate, investmentTimePeriod ) // pass the data to view by accepting the context of the view class sipCalculatorViewInterface.onCalculationResult( sipModel.getTotalInvestedAmount().toString(), sipModel.getEstimatedReturns().toString(), sipModel.getTotalValue().toString() ) } } |
Step 7: Working with SipCalculatorView.kt class
This class implements the SipCalculatorViewInterface and the context of this class is provided to the Presenter class to get the calculated result. And it creates instances of each UI element and after getting calculated results from the presenter it updates UI elements. To implement the same invoke the following code inside the SipCalculatorView.kt class. Comments are added for better understanding.
Kotlin
import android.annotation.SuppressLint import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import androidx.core.content.ContextCompat import com.adityamshidlyali.gfgsipcalculator.Presenter.SipCalculatorPresenter import com.adityamshidlyali.gfgsipcalculator.R import com.google.android.material.button.MaterialButton import com.google.android.material.slider.Slider import com.google.android.material.textfield.TextInputEditText import com.google.android.material.textfield.TextInputLayout import com.google.android.material.textview.MaterialTextView import org.eazegraph.lib.charts.PieChart import org.eazegraph.lib.models.PieModel import java.text.NumberFormat import java.util.* class SipCalculatorView : AppCompatActivity(), SipCalculatorViewInterface { // material text views private lateinit var totalInvestedAmountMaterialTextView: MaterialTextView private lateinit var estimatedReturnsMaterialTextView: MaterialTextView private lateinit var totalAmountMaterialTextView: MaterialTextView // material text input edit texts and text input layout private lateinit var monthlyInvestmentAmountTextInputEditText: TextInputEditText private lateinit var expectedReturnRateTextInputEditText: TextInputEditText private lateinit var investmentTimePeriodTextInputEditText: TextInputEditText private lateinit var monthlyInvestmentAmountTextInputLayout: TextInputLayout private lateinit var expectedReturnRateTextInputLayout: TextInputLayout private lateinit var investmentTimePeriodTextInputLayout: TextInputLayout // buttons private lateinit var sipCalculateResultButton: MaterialButton // pie chart private lateinit var sipResultPieChart: PieChart // calculation result strings private lateinit var monthlyInvestmentAmount: String private lateinit var expectedReturnRate: String private lateinit var investmentTimePeriod: String // sliders private lateinit var monthlyInvestmentAmountSlider: Slider private lateinit var expectedReturnRateSlider: Slider private lateinit var investmentTimePeriodSlider: Slider @SuppressLint ( "UseCompatLoadingForDrawables" , "SetTextI18n" ) override fun onCreate(savedInstanceState: Bundle?) { super .onCreate(savedInstanceState) setContentView(R.layout.activity_main) // initialise all the UI elements // material textViews totalInvestedAmountMaterialTextView = findViewById(R.id.totalInvestedAmountMaterialTextView) estimatedReturnsMaterialTextView = findViewById(R.id.estimatedReturnsMaterialTextView) totalAmountMaterialTextView = findViewById(R.id.totalAmountMaterialTextView) // material text input editTexts and text input layout monthlyInvestmentAmountTextInputEditText = findViewById(R.id.monthlyInvestmentAmountTextInputEditText) expectedReturnRateTextInputEditText = findViewById(R.id.expectedReturnRateTextInputEditText) investmentTimePeriodTextInputEditText = findViewById(R.id.investmentTimePeriodTextInputEditText) monthlyInvestmentAmountTextInputLayout = findViewById(R.id.monthlyInvestmentAmountTextInputLayout) expectedReturnRateTextInputLayout = findViewById(R.id.expectedReturnRateTextInputLayout) investmentTimePeriodTextInputLayout = findViewById(R.id.investmentTimePeriodTextInputLayout) // buttons sipCalculateResultButton = findViewById(R.id.sipCalculateResultButton) // pie chart sipResultPieChart = findViewById(R.id.sipResultPieChart) // sliders monthlyInvestmentAmountSlider = findViewById(R.id.monthlyInvestmentAmountSlider) expectedReturnRateSlider = findViewById(R.id.expectedReturnRateSlider) investmentTimePeriodSlider = findViewById(R.id.investmentTimePeriodSlider) // setting initial values to all the UI elements // TextInputEditTexts monthlyInvestmentAmountTextInputEditText.setText( "5000" ) expectedReturnRateTextInputEditText.setText( "14" ) investmentTimePeriodTextInputEditText.setText( "10" ) // sliders monthlyInvestmentAmountSlider.value = 5000f expectedReturnRateSlider.value = 14f investmentTimePeriodSlider.value = 10f val sipPresenter = SipCalculatorPresenter( this ) sipPresenter.forCalculation( "5000" , "14" , "10" ) // handling all listeners for all the UI elements // handling sliders monthlyInvestmentAmountSlider.addOnChangeListener { slider, value, fromUser -> monthlyInvestmentAmountTextInputEditText.setText(value.toInt().toString()) } expectedReturnRateSlider.addOnChangeListener { slider, value, fromUser -> expectedReturnRateTextInputEditText.setText(value.toInt().toString()) } investmentTimePeriodSlider.addOnChangeListener { slider, value, fromUser -> investmentTimePeriodTextInputEditText.setText(value.toInt().toString()) } // handling buttons sipCalculateResultButton.setOnClickListener { monthlyInvestmentAmount = monthlyInvestmentAmountTextInputEditText.text.toString() expectedReturnRate = expectedReturnRateTextInputEditText.text.toString() investmentTimePeriod = investmentTimePeriodTextInputEditText.text.toString() if (checkAllFields()) { sipPresenter.forCalculation( monthlyInvestmentAmount, expectedReturnRate, investmentTimePeriod ) } } } // update the text views in the // result section of the view // and also update the pie chart override fun onCalculationResult( totalInvestedAmount: String, estimatedReturns: String, totalValue: String ) { val currencyFormatter: NumberFormat = NumberFormat.getCurrencyInstance(Locale( "en" , "IN" , "#" )) val totalInvestedAmountFormatted: String = currencyFormatter.format(totalInvestedAmount.toLong()) val estimatedReturnsFormatted: String = currencyFormatter.format(estimatedReturns.toLong()) val totalValueFormatted: String = currencyFormatter.format(totalValue.toLong()) totalInvestedAmountMaterialTextView.text = totalInvestedAmountFormatted estimatedReturnsMaterialTextView.text = estimatedReturnsFormatted totalAmountMaterialTextView.text = totalValueFormatted sipResultPieChart.clearAnimation() sipResultPieChart.clearChart() sipResultPieChart.addPieSlice( PieModel( "Invested Amount" , totalInvestedAmount.toFloat(), ContextCompat.getColor( this , R.color.blue_200) ) ) sipResultPieChart.addPieSlice( PieModel( "Estimated Returns" , totalValue.toFloat() - totalInvestedAmount.toFloat(), ContextCompat.getColor( this , R.color.green_200) ) ) sipResultPieChart.startAnimation() } // check whether all the text fields are filled or not private fun checkAllFields(): Boolean { if (monthlyInvestmentAmount.isEmpty()) { monthlyInvestmentAmountTextInputEditText.error = "Can't be empty" return false } if (expectedReturnRate.isEmpty()) { expectedReturnRateTextInputEditText.error = "Can't be empty" return false } if (investmentTimePeriod.isEmpty()) { investmentTimePeriodTextInputEditText.error = "Can't be empty" return false } return true } } |
Output: