Skip to content

Commit

Permalink
Merge pull request #841 from toastkidjp/feature/#818_loan
Browse files Browse the repository at this point in the history
Feature/#818 loan
  • Loading branch information
toastkidjp authored Feb 13, 2022
2 parents 6710cd1 + f2f869a commit f002e32
Show file tree
Hide file tree
Showing 19 changed files with 577 additions and 3 deletions.
1 change: 1 addition & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ dependencies {
implementation project(":api")
implementation project(":rss")
implementation project(":image")
implementation project(":loan")

implementation "androidx.appcompat:appcompat:$libVersions.appcompat"
implementation "androidx.cardview:cardview:$libVersions.cardview"
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/jp/toastkid/yobidashi/menu/Menu.kt
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ enum class Menu(

WHAT_HAPPENED_TODAY(R.string.menu_what_happened_today, R.drawable.ic_what_happened_today),

LOAN_CALCULATOR(R.string.title_loan_calculator, R.drawable.ic_loan_calculator),

PLANNING_POKER(R.string.title_planning_poker, R.drawable.ic_card),

GESTURE_MEMO(R.string.title_gesture_memo, R.drawable.ic_gesture_memo),
Expand Down
4 changes: 4 additions & 0 deletions app/src/main/java/jp/toastkid/yobidashi/menu/MenuUseCase.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import jp.toastkid.lib.BrowserViewModel
import jp.toastkid.lib.ContentViewModel
import jp.toastkid.lib.Urls
import jp.toastkid.lib.preference.PreferenceApplier
import jp.toastkid.loan.view.LoanCalculatorFragment
import jp.toastkid.media.music.popup.MediaPlayerPopup
import jp.toastkid.planning.CardListFragment
import jp.toastkid.rss.RssReaderFragment
Expand Down Expand Up @@ -89,6 +90,9 @@ class MenuUseCase(
}
return
}
Menu.LOAN_CALCULATOR-> {
nextFragment(LoanCalculatorFragment::class.java)
}
Menu.PLANNING_POKER-> {
nextFragment(CardListFragment::class.java)
}
Expand Down
1 change: 0 additions & 1 deletion app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,5 @@
<string name="hourly_trends">Hourly trends</string>
<string name="sample_text_color_filter">A</string>
<string name="message_backup_is_empty">Backup is empty.</string>
<string name="title_loan">Loan calculator</string>

</resources>
1 change: 1 addition & 0 deletions loan/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
46 changes: 46 additions & 0 deletions loan/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright (c) 2021 toastkidjp.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompany this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html.
*/

plugins {
id 'com.android.library'
id 'kotlin-android'
id 'kotlin-kapt'
}
android {
compileSdkVersion rootProject.ext.compileSdk

defaultConfig {
minSdkVersion rootProject.ext.minSdk
targetSdkVersion 31
versionCode 1
versionName "1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
buildFeatures.dataBinding = true
}

dependencies {
implementation project(":lib")

implementation "androidx.appcompat:appcompat:$libVersions.appcompat"
implementation "androidx.cardview:cardview:$libVersions.cardview"
implementation "androidx.constraintlayout:constraintlayout:$libVersions.constraintlayout"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$libVersions.coroutines"
implementation "com.google.android.material:material:$libVersions.material"

testImplementation "junit:junit:$libVersions.junit"
testImplementation "io.mockk:mockk:$libVersions.mockk"
}
5 changes: 5 additions & 0 deletions loan/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="jp.toastkid.loan">

</manifest>
44 changes: 44 additions & 0 deletions loan/src/main/java/jp/toastkid/loan/Calculator.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright (c) 2021 toastkidjp.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompany this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html.
*/

package jp.toastkid.loan

import jp.toastkid.loan.model.Factor
import kotlin.math.max
import kotlin.math.pow

class Calculator {

operator fun invoke(factor: Factor) = invoke(
factor.amount,
factor.term,
factor.interestRate,
factor.downPayment,
factor.managementFee,
factor.renovationReserves
)

operator fun invoke(
amount: Int,
term: Int,
interestRate: Double,
downPayment: Int,
managementFee: Int,
renovationReserves: Int
): Int {
val paymentCount = (term * 12).toDouble()
val convertedRate = interestRate / 100.0
val poweredMonthlyInterestRate = (1 + convertedRate / 12).pow(paymentCount)

val numerator = ((amount - downPayment) * convertedRate) / 12 * poweredMonthlyInterestRate
val denominator = poweredMonthlyInterestRate - 1

return (max(numerator / denominator, 0.0)).toInt() + managementFee + renovationReserves
}

}
18 changes: 18 additions & 0 deletions loan/src/main/java/jp/toastkid/loan/model/Factor.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright (c) 2021 toastkidjp.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompany this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html.
*/

package jp.toastkid.loan.model

class Factor(
val amount: Int,
val term: Int,
val interestRate: Double,
val downPayment: Int,
val managementFee: Int,
val renovationReserves: Int
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright (c) 2021 toastkidjp.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompany this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html.
*/

package jp.toastkid.loan.usecase

import jp.toastkid.loan.Calculator
import jp.toastkid.loan.model.Factor
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.launch

class DebouncedCalculatorUseCase(
private val inputChannel: Channel<String>,
private val currentFactorProvider: () -> Factor,
private val onResult: (Int) -> Unit,
private val calculator: Calculator = Calculator(),
private val debounceMillis: Long = 1000,
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO,
private val mainDispatcher: CoroutineDispatcher = Dispatchers.Main
) {

@FlowPreview
operator fun invoke() {
CoroutineScope(ioDispatcher).launch {
inputChannel
.receiveAsFlow()
.distinctUntilChanged()
.debounce(debounceMillis)
.flowOn(mainDispatcher)
.collect {
val factor = currentFactorProvider()
val payment = calculator(
factor.amount,
factor.term,
factor.interestRate,
factor.downPayment,
factor.managementFee,
factor.renovationReserves
)

onResult(payment)
}
}
}

}
96 changes: 96 additions & 0 deletions loan/src/main/java/jp/toastkid/loan/view/LoanCalculatorFragment.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* Copyright (c) 2021 toastkidjp.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompany this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html.
*/

package jp.toastkid.loan.view

import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.EditText
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
import jp.toastkid.loan.R
import jp.toastkid.loan.databinding.FragmentLoanCalculatorBinding
import jp.toastkid.loan.model.Factor
import jp.toastkid.loan.usecase.DebouncedCalculatorUseCase
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.launch

class LoanCalculatorFragment : Fragment() {

private var binding: FragmentLoanCalculatorBinding? = null

private val inputChannel: Channel<String> = Channel()

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_loan_calculator, container, false)
return binding?.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

val textWatcher = object : TextWatcher {

override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) = Unit

override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
CoroutineScope(Dispatchers.IO).launch {
inputChannel.send(s?.toString() ?: "")
}
}

override fun afterTextChanged(s: Editable?) = Unit

}

binding?.loanAmount?.addTextChangedListener(textWatcher)
binding?.term?.addTextChangedListener(textWatcher)
binding?.interestRate?.addTextChangedListener(textWatcher)
binding?.downPayment?.addTextChangedListener(textWatcher)
binding?.monthlyManagementFee?.addTextChangedListener(textWatcher)
binding?.monthlyRenovationReserves?.addTextChangedListener(textWatcher)


DebouncedCalculatorUseCase(
inputChannel,
{
Factor(
extractInt(binding?.loanAmount),
extractInt(binding?.term),
extractDouble(binding?.interestRate),
extractInt(binding?.downPayment),
extractInt(binding?.monthlyManagementFee),
extractInt(binding?.monthlyRenovationReserves)
)
},
{ binding?.result?.text = getString(R.string.message_result_montly_payment, it) }
).invoke()
}

private fun extractInt(editText: EditText?) =
editText?.text?.toString()?.toIntOrNull() ?: 0

private fun extractDouble(editText: EditText?) =
editText?.text?.toString()?.toDoubleOrNull() ?: 0.0

override fun onDetach() {
binding = null
super.onDetach()
}

}
5 changes: 5 additions & 0 deletions loan/src/main/res/drawable/ic_loan_calculator.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M19,14L19,6c0,-1.1 -0.9,-2 -2,-2L3,4c-1.1,0 -2,0.9 -2,2v8c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2zM10,13c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3 3,1.34 3,3 -1.34,3 -3,3zM23,7v11c0,1.1 -0.9,2 -2,2L4,20v-2h17L21,7h2z"/>
</vector>
Loading

0 comments on commit f002e32

Please sign in to comment.