Open In App

How to Build SIP Calculator Android App using MVP Architecture?

Improve
Improve
Like Article
Like
Save
Share
Report

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.

Build SIP Calculator Android App using MVP Architecture

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:

  1. It determines the total amount invested over time.
  2. Tells about estimated returns over the expected rate of return.
  3. 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

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: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:



Last Updated : 18 Oct, 2021
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads