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 version = "1.0" encoding = "utf-8" ?>
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.
<!-- 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:
interface SipCalculatorModelInterface {
fun getTotalInvestedAmount(): Long
fun getEstimatedReturns(): Long
fun getTotalValue(): Long
} |
SipCalculatorPresenterInterface:
interface SipCalculatorPresenterInterface {
fun forCalculation(
monthlyInvestmentAmount: String,
expectedReturnRate: String,
investmentTimePeriod: String
)
} |
SipCalculatorViewInterface:
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.
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.
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.
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: