Skip to content

Commit

Permalink
added emi detail screen
Browse files Browse the repository at this point in the history
  • Loading branch information
suyash01 committed Jan 27, 2024
1 parent 22e70c9 commit b950bcd
Show file tree
Hide file tree
Showing 7 changed files with 282 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.suyash.creditmanager.presentation.emi_details

sealed class EMIDetailEvent {
data object BackPressed: EMIDetailEvent()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
package com.suyash.creditmanager.presentation.emi_details

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material3.Divider
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavController
import com.suyash.creditmanager.presentation.util.CMUtils
import kotlinx.coroutines.flow.collectLatest

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun EMIDetailScreen(
navController: NavController,
viewModel: EMIDetailViewModel = hiltViewModel()
) {
val snackbarHostState = remember { SnackbarHostState() }

LaunchedEffect(key1 = true) {
viewModel.eventFlow.collectLatest { event ->
when(event) {
is EMIDetailViewModel.UiEvent.ShowSnackbar -> {
snackbarHostState.showSnackbar(
message = event.message
)
}
is EMIDetailViewModel.UiEvent.NavigateUp -> {
navController.navigateUp()
}
}
}
}

Scaffold(
snackbarHost = {
SnackbarHost(hostState = snackbarHostState)
},
topBar = {
TopAppBar(
title = {
Text(text = "EMI Detail")
},
navigationIcon = {
IconButton(onClick = {
viewModel.onEvent(EMIDetailEvent.BackPressed)
}) {
Icon(
Icons.Filled.ArrowBack,
contentDescription = "Go Back"
)
}
}
)
}
) { paddingValues ->
Column(
modifier = Modifier
.padding(paddingValues)
.fillMaxWidth()
.padding(16.dp)
) {
Text(
text = viewModel.emi?.name?:"",
style = MaterialTheme.typography.titleLarge,
color = MaterialTheme.colorScheme.primary
)
Spacer(modifier = Modifier.height(8.dp))
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = CMUtils.currencyMask(viewModel.emi?.amount?:0.0F, viewModel.countryCode),
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.primary
)
viewModel.creditCard?.let {
Text(
text = "${it.cardName} (${it.last4Digits})",
style = MaterialTheme.typography.bodySmall,
)
}
}
Spacer(modifier = Modifier.height(8.dp))
Text(
text = CMUtils.currencyMask(viewModel.emiAmount, viewModel.countryCode),
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.primary
)
Spacer(modifier = Modifier.height(16.dp))
Divider()
LazyColumn {
itemsIndexed(viewModel.schedule) {i, schedule ->
Row(
modifier = Modifier.fillMaxWidth().padding(top = 16.dp),
verticalAlignment = Alignment.CenterVertically
) {
Text(text = (i+1).toString())
Column(
modifier = Modifier
.padding(start = 16.dp)
.weight(1f)
) {
Text(
text = CMUtils.currencyMask(schedule.principal, viewModel.countryCode),
style = MaterialTheme.typography.bodySmall
)
Spacer(modifier = Modifier.height(8.dp))
Text(
text = CMUtils.currencyMask(schedule.interest, viewModel.countryCode),
style = MaterialTheme.typography.bodySmall
)
}
Text(
text = CMUtils.currencyMask(schedule.amount, viewModel.countryCode),
color = MaterialTheme.colorScheme.primary
)
}
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package com.suyash.creditmanager.presentation.emi_details

import androidx.datastore.core.DataStore
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.suyash.creditmanager.data.settings.AppSettings
import com.suyash.creditmanager.domain.model.CreditCard
import com.suyash.creditmanager.domain.model.EMI
import com.suyash.creditmanager.domain.use_case.CreditCardUseCases
import com.suyash.creditmanager.domain.use_case.EMIUseCases
import com.suyash.creditmanager.domain.util.DateFormat
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.launch
import javax.inject.Inject
import kotlin.math.pow

@HiltViewModel
class EMIDetailViewModel @Inject constructor(
private val creditCardUseCases: CreditCardUseCases,
private val emiUseCases: EMIUseCases,
private val dataStore: DataStore<AppSettings>,
savedStateHandle: SavedStateHandle
): ViewModel() {

var emi: EMI? = null
var creditCard: CreditCard? = null
var countryCode: String = "IN"
var dateFormat: DateFormat = DateFormat.DDMMYYYY
var emiAmount: Float = 0.0F
var schedule: List<EMISchedule> = emptyList()

private val _eventFlow = MutableSharedFlow<UiEvent>()
val eventFlow = _eventFlow.asSharedFlow()

init {
savedStateHandle.get<Int>("emiId")?.let {
viewModelScope.launch {
emiUseCases.getEMI(it)?.also { e ->
emi = e
calculateEMISchedule(e.amount, e.rate, e.months)
}
emi?.card?.let {
creditCardUseCases.getCreditCard(it)?.also { cc ->
creditCard = cc
}
}
dataStore.data.collect {
countryCode = it.countryCode
dateFormat = it.dateFormat
}
}
}
}

fun onEvent(event: EMIDetailEvent) {
when (event) {
is EMIDetailEvent.BackPressed -> {
viewModelScope.launch {
_eventFlow.emit(UiEvent.NavigateUp)
}
}
}
}

private fun calculateEMISchedule(startingAmount: Float, interestRate: Float, tenure: Int) {
val schedule: MutableList<EMISchedule> = mutableListOf()
var principal: Float = startingAmount
val monthlyRate: Float = interestRate/1200
val emi: Float = startingAmount*monthlyRate*(1+monthlyRate).pow(tenure)/((1+monthlyRate).pow(tenure)-1)
for (i in 1..tenure) {
val interest = principal*(monthlyRate)
val principalPaid: Float = emi - interest
principal -= principalPaid
schedule.add(EMISchedule(principalPaid, interest, principal))
}
this.emiAmount = emi
this.schedule = schedule.toList()
}

data class EMISchedule(
val principal: Float,
val interest: Float,
val amount: Float
)

sealed class UiEvent {
data class ShowSnackbar(val message: String): UiEvent()
data object NavigateUp: UiEvent()
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.suyash.creditmanager.presentation.emis

import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
Expand All @@ -20,7 +22,7 @@ import com.suyash.creditmanager.presentation.emis.component.EMIItem
import com.suyash.creditmanager.presentation.util.Screen

@Composable
@OptIn(ExperimentalMaterial3Api::class)
@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
fun EMIsScreen(
navController: NavController,
viewModel: EMIsViewModel = hiltViewModel()
Expand Down Expand Up @@ -49,7 +51,18 @@ fun EMIsScreen(
emi = emi,
countryCode = viewModel.state.value.countryCode,
dateFormat = viewModel.state.value.dateFormat,
modifier = Modifier.fillMaxWidth()
modifier = Modifier
.fillMaxWidth()
.combinedClickable(
onClick = {
navController.navigate(
Screen.EMIDetailScreen.route + "?emiId=" + emi.id
)
},
onLongClick = {
// TODO impl
}
)
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ fun EMIItem(
Column(
modifier = Modifier
.fillMaxWidth()
.padding(start = 16.dp)
) {
Row(
modifier = Modifier.fillMaxWidth(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import com.suyash.creditmanager.presentation.add_edit_cc.AddEditCCScreen
import com.suyash.creditmanager.presentation.add_edit_emis.AddEditEMIScreen
import com.suyash.creditmanager.presentation.add_edit_txn.AddEditTxnScreen
import com.suyash.creditmanager.presentation.credit_cards.CreditCardsScreen
import com.suyash.creditmanager.presentation.emi_details.EMIDetailScreen
import com.suyash.creditmanager.presentation.emis.EMIsScreen
import com.suyash.creditmanager.presentation.settings.SettingsScreen
import com.suyash.creditmanager.presentation.transactions.TransactionsScreen
Expand Down Expand Up @@ -115,6 +116,17 @@ fun CreditManager() {
) {
AddEditEMIScreen(navController = navController)
}
composable(
route = Screen.EMIDetailScreen.route + "?emiId={emiId}",
arguments = listOf(
navArgument(name = "emiId") {
type = NavType.IntType
defaultValue = -1
}
)
) {
EMIDetailScreen(navController = navController)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ package com.suyash.creditmanager.presentation.util
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.CreditCard
import androidx.compose.material.icons.filled.Info
import androidx.compose.material.icons.filled.Payments
import androidx.compose.material.icons.filled.Receipt
import androidx.compose.material.icons.filled.Settings
import androidx.compose.material.icons.outlined.Add
import androidx.compose.material.icons.outlined.CreditCard
import androidx.compose.material.icons.outlined.Info
import androidx.compose.material.icons.outlined.Payments
import androidx.compose.material.icons.outlined.Receipt
import androidx.compose.material.icons.outlined.Settings
Expand Down Expand Up @@ -63,6 +65,13 @@ sealed class Screen(
Icons.Outlined.Add
)

data object EMIDetailScreen: Screen(
"emi_detail",
"EMI Detail",
Icons.Filled.Info,
Icons.Outlined.Info
)

companion object {
val bottomBarScreens: List<Screen> = listOf(
CreditCardsScreen,
Expand Down

0 comments on commit b950bcd

Please sign in to comment.