From a67391483b40aea055654245c90325070a4a6a04 Mon Sep 17 00:00:00 2001 From: Suyash Mittal Date: Mon, 17 Jun 2024 02:45:29 +0530 Subject: [PATCH] added indexing and txn category support --- app/build.gradle.kts | 4 +- .../6.json | 279 ++++++++++++++++++ .../data/source/CreditDatabase.kt | 5 +- .../suyash/creditmanager/domain/model/EMI.kt | 13 +- .../creditmanager/domain/model/Transaction.kt | 11 +- .../add_edit_cc/AddEditCCEvent.kt | 2 + .../add_edit_cc/AddEditCCScreen.kt | 72 +++-- .../add_edit_cc/AddEditCCViewModel.kt | 7 + .../add_edit_txn/AddEditTxnEvent.kt | 1 + .../add_edit_txn/AddEditTxnScreen.kt | 40 +++ .../add_edit_txn/AddEditTxnViewModel.kt | 25 +- .../credit_cards/component/CreditCardItem.kt | 3 +- .../presentation/emis/component/EMIItem.kt | 3 +- .../transactions/TransactionsScreen.kt | 21 +- .../transactions/component/TransactionItem.kt | 8 +- 15 files changed, 444 insertions(+), 50 deletions(-) create mode 100644 app/schemas/com.suyash.creditmanager.data.source.CreditDatabase/6.json diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 849a973..4b4fde9 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -15,8 +15,8 @@ android { applicationId = "com.suyash.creditmanager" minSdk = 26 targetSdk = 34 - versionCode = 18 - versionName = "1.0.17" + versionCode = 19 + versionName = "1.0.18" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { diff --git a/app/schemas/com.suyash.creditmanager.data.source.CreditDatabase/6.json b/app/schemas/com.suyash.creditmanager.data.source.CreditDatabase/6.json new file mode 100644 index 0000000..fd8a255 --- /dev/null +++ b/app/schemas/com.suyash.creditmanager.data.source.CreditDatabase/6.json @@ -0,0 +1,279 @@ +{ + "formatVersion": 1, + "database": { + "version": 6, + "identityHash": "a01cc184bd915b8ffd052c502e6e084d", + "entities": [ + { + "tableName": "credit_cards", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`cardName` TEXT NOT NULL, `last4Digits` TEXT NOT NULL, `expiryDate` TEXT NOT NULL, `billDate` INTEGER NOT NULL, `dueDate` INTEGER NOT NULL, `cardType` TEXT NOT NULL, `limit` INTEGER NOT NULL, `bankName` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)", + "fields": [ + { + "fieldPath": "cardName", + "columnName": "cardName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "last4Digits", + "columnName": "last4Digits", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "expiryDate", + "columnName": "expiryDate", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billDate", + "columnName": "billDate", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dueDate", + "columnName": "dueDate", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "cardType", + "columnName": "cardType", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "limit", + "columnName": "limit", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "bankName", + "columnName": "bankName", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "transactions", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`type` TEXT NOT NULL, `amount` REAL NOT NULL, `card` INTEGER NOT NULL, `date` TEXT NOT NULL, `category` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`card`) REFERENCES `credit_cards`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "amount", + "columnName": "amount", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "card", + "columnName": "card", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "category", + "columnName": "category", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "index_transactions_date", + "unique": false, + "columnNames": [ + "date" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_transactions_date` ON `${TABLE_NAME}` (`date`)" + }, + { + "name": "index_transactions_card", + "unique": false, + "columnNames": [ + "card" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_transactions_card` ON `${TABLE_NAME}` (`card`)" + } + ], + "foreignKeys": [ + { + "table": "credit_cards", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "card" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "emis", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `amount` REAL NOT NULL, `rate` REAL NOT NULL, `months` INTEGER NOT NULL, `card` INTEGER, `date` TEXT NOT NULL, `taxRate` REAL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`card`) REFERENCES `credit_cards`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "amount", + "columnName": "amount", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "rate", + "columnName": "rate", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "months", + "columnName": "months", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "card", + "columnName": "card", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "taxRate", + "columnName": "taxRate", + "affinity": "REAL", + "notNull": false + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "index_emis_card", + "unique": false, + "columnNames": [ + "card" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_emis_card` ON `${TABLE_NAME}` (`card`)" + } + ], + "foreignKeys": [ + { + "table": "credit_cards", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "card" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "txn_categories", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`type` TEXT NOT NULL, `name` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)", + "fields": [ + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'a01cc184bd915b8ffd052c502e6e084d')" + ] + } +} \ No newline at end of file diff --git a/app/src/main/java/com/suyash/creditmanager/data/source/CreditDatabase.kt b/app/src/main/java/com/suyash/creditmanager/data/source/CreditDatabase.kt index ebe9192..9e13bf1 100644 --- a/app/src/main/java/com/suyash/creditmanager/data/source/CreditDatabase.kt +++ b/app/src/main/java/com/suyash/creditmanager/data/source/CreditDatabase.kt @@ -14,12 +14,13 @@ import com.suyash.creditmanager.domain.model.TxnCategory @Database( entities = [CreditCard::class, Transaction::class, EMI::class, TxnCategory::class], - version = 5, + version = 6, autoMigrations = [ AutoMigration(from = 1, to = 2), AutoMigration(from = 2, to = 3), AutoMigration(from = 3, to = 4), - AutoMigration(from = 4, to = 5) + AutoMigration(from = 4, to = 5), + AutoMigration(from = 5, to = 6) ] ) abstract class CreditDatabase: RoomDatabase() { diff --git a/app/src/main/java/com/suyash/creditmanager/domain/model/EMI.kt b/app/src/main/java/com/suyash/creditmanager/domain/model/EMI.kt index 73f6abd..20e65b0 100644 --- a/app/src/main/java/com/suyash/creditmanager/domain/model/EMI.kt +++ b/app/src/main/java/com/suyash/creditmanager/domain/model/EMI.kt @@ -1,6 +1,8 @@ package com.suyash.creditmanager.domain.model import androidx.room.Entity +import androidx.room.ForeignKey +import androidx.room.Index import androidx.room.PrimaryKey import androidx.room.TypeConverters import com.suyash.creditmanager.domain.model.backup.EmiBackup @@ -9,7 +11,16 @@ import java.time.temporal.ChronoUnit import kotlin.math.min @Entity( - tableName = "emis" + tableName = "emis", + indices = [Index(value = ["card"])], + foreignKeys = [ + ForeignKey( + entity = CreditCard::class, + parentColumns = ["id"], + childColumns = ["card"], + onDelete = ForeignKey.CASCADE + ) + ] ) @TypeConverters(Converters::class) data class EMI( diff --git a/app/src/main/java/com/suyash/creditmanager/domain/model/Transaction.kt b/app/src/main/java/com/suyash/creditmanager/domain/model/Transaction.kt index 7843b1d..6c5268d 100644 --- a/app/src/main/java/com/suyash/creditmanager/domain/model/Transaction.kt +++ b/app/src/main/java/com/suyash/creditmanager/domain/model/Transaction.kt @@ -1,6 +1,7 @@ package com.suyash.creditmanager.domain.model import androidx.room.Entity +import androidx.room.ForeignKey import androidx.room.Index import androidx.room.PrimaryKey import androidx.room.TypeConverters @@ -10,7 +11,15 @@ import java.time.LocalDate @Entity( tableName = "transactions", - indices = [Index(value = ["date"])] + indices = [Index(value = ["date"]), Index(value = ["card"])], + foreignKeys = [ + ForeignKey( + entity = CreditCard::class, + parentColumns = ["id"], + childColumns = ["card"], + onDelete = ForeignKey.CASCADE + ) + ] ) @TypeConverters(Converters::class) data class Transaction( diff --git a/app/src/main/java/com/suyash/creditmanager/presentation/add_edit_cc/AddEditCCEvent.kt b/app/src/main/java/com/suyash/creditmanager/presentation/add_edit_cc/AddEditCCEvent.kt index 759c210..8aeffcd 100644 --- a/app/src/main/java/com/suyash/creditmanager/presentation/add_edit_cc/AddEditCCEvent.kt +++ b/app/src/main/java/com/suyash/creditmanager/presentation/add_edit_cc/AddEditCCEvent.kt @@ -11,6 +11,8 @@ sealed class AddEditCCEvent { data class EnteredDueDate(val value: String): AddEditCCEvent() data class EnteredLimit(val value: String): AddEditCCEvent() data class EnteredBankName(val value: String): AddEditCCEvent() + data class CheckedGracePeriod(val value: Boolean): AddEditCCEvent() + data object UpsertCreditCard: AddEditCCEvent() data object BackPressed: AddEditCCEvent() } diff --git a/app/src/main/java/com/suyash/creditmanager/presentation/add_edit_cc/AddEditCCScreen.kt b/app/src/main/java/com/suyash/creditmanager/presentation/add_edit_cc/AddEditCCScreen.kt index d58556e..8c0e9aa 100644 --- a/app/src/main/java/com/suyash/creditmanager/presentation/add_edit_cc/AddEditCCScreen.kt +++ b/app/src/main/java/com/suyash/creditmanager/presentation/add_edit_cc/AddEditCCScreen.kt @@ -1,6 +1,8 @@ package com.suyash.creditmanager.presentation.add_edit_cc +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 @@ -12,6 +14,7 @@ import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.filled.Done +import androidx.compose.material3.Checkbox import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExposedDropdownMenuBox @@ -31,6 +34,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusDirection import androidx.compose.ui.platform.LocalFocusManager @@ -194,33 +198,51 @@ fun AddEditCCScreen( keyboardActions = KeyboardActions(onNext = { focusManager.moveFocus(FocusDirection.Down) }) ) Spacer(modifier = Modifier.height(16.dp)) - OutlinedTextField( + Row( modifier = Modifier.fillMaxWidth(), - value = viewModel.dueDate.value, - onValueChange = { newText -> - viewModel.onEvent(AddEditCCEvent.EnteredDueDate(newText)) - }, - label = { Text("Due Date") }, - keyboardOptions = KeyboardOptions.Default.copy( - keyboardType = KeyboardType.Number, - imeAction = ImeAction.Next - ), - keyboardActions = KeyboardActions(onNext = { focusManager.moveFocus(FocusDirection.Down) }) - ) + verticalAlignment = Alignment.CenterVertically, + ) { + Checkbox( + checked = viewModel.gracePeriod.value, + onCheckedChange = { viewModel.onEvent(AddEditCCEvent.CheckedGracePeriod(it)) } + ) + Text( + "Grace period instead of bill date" + ) + } Spacer(modifier = Modifier.height(16.dp)) - OutlinedTextField( + Row( modifier = Modifier.fillMaxWidth(), - value = viewModel.billDate.value, - onValueChange = { newText -> - viewModel.onEvent(AddEditCCEvent.EnteredBillDate(newText)) - }, - label = { Text("Bill Date") }, - keyboardOptions = KeyboardOptions.Default.copy( - keyboardType = KeyboardType.Number, - imeAction = ImeAction.Next - ), - keyboardActions = KeyboardActions(onNext = { focusManager.moveFocus(FocusDirection.Down) }) - ) + horizontalArrangement = Arrangement.spacedBy(16.dp) + ) { + OutlinedTextField( + modifier = Modifier.weight(1f), + value = viewModel.dueDate.value, + onValueChange = { newText -> + viewModel.onEvent(AddEditCCEvent.EnteredDueDate(newText)) + }, + label = { Text("Due Date") }, + keyboardOptions = KeyboardOptions.Default.copy( + keyboardType = KeyboardType.Number, + imeAction = ImeAction.Next + ), + keyboardActions = KeyboardActions(onNext = { focusManager.moveFocus(FocusDirection.Down) }) + ) + Spacer(modifier = Modifier.height(16.dp)) + OutlinedTextField( + modifier = Modifier.weight(1f), + value = viewModel.billDate.value, + onValueChange = { newText -> + viewModel.onEvent(AddEditCCEvent.EnteredBillDate(newText)) + }, + label = { Text(if(viewModel.gracePeriod.value) "Grace Period" else "Bill Date") }, + keyboardOptions = KeyboardOptions.Default.copy( + keyboardType = KeyboardType.Number, + imeAction = ImeAction.Next + ), + keyboardActions = KeyboardActions(onNext = { focusManager.moveFocus(FocusDirection.Down) }) + ) + } Spacer(modifier = Modifier.height(16.dp)) OutlinedTextField( modifier = Modifier.fillMaxWidth(), @@ -259,4 +281,4 @@ fun AddEditCCScreen( ) } } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/suyash/creditmanager/presentation/add_edit_cc/AddEditCCViewModel.kt b/app/src/main/java/com/suyash/creditmanager/presentation/add_edit_cc/AddEditCCViewModel.kt index 066442e..0e838ca 100644 --- a/app/src/main/java/com/suyash/creditmanager/presentation/add_edit_cc/AddEditCCViewModel.kt +++ b/app/src/main/java/com/suyash/creditmanager/presentation/add_edit_cc/AddEditCCViewModel.kt @@ -36,6 +36,9 @@ class AddEditCCViewModel @Inject constructor( private val _expiry = mutableStateOf("") val expiry: State = _expiry + private val _gracePeriod = mutableStateOf(false) + val gracePeriod: State = _gracePeriod + private val _billDate = mutableStateOf("") val billDate: State = _billDate @@ -110,6 +113,10 @@ class AddEditCCViewModel @Inject constructor( } } + is AddEditCCEvent.CheckedGracePeriod -> { + _gracePeriod.value = event.value + } + is AddEditCCEvent.EnteredDueDate -> { if (event.value.isEmpty()) { _dueDate.value = event.value diff --git a/app/src/main/java/com/suyash/creditmanager/presentation/add_edit_txn/AddEditTxnEvent.kt b/app/src/main/java/com/suyash/creditmanager/presentation/add_edit_txn/AddEditTxnEvent.kt index 34af35d..f382d15 100644 --- a/app/src/main/java/com/suyash/creditmanager/presentation/add_edit_txn/AddEditTxnEvent.kt +++ b/app/src/main/java/com/suyash/creditmanager/presentation/add_edit_txn/AddEditTxnEvent.kt @@ -7,6 +7,7 @@ import java.time.LocalDate sealed class AddEditTxnEvent { data class SelectedCard(val value: CreditCard): AddEditTxnEvent() data class SelectedTxnType(val value: TransactionType): AddEditTxnEvent() + data class SelectedTxnCategory(val value: String): AddEditTxnEvent() data class EnteredAmount(val value: String): AddEditTxnEvent() data class EnteredDate(val value: LocalDate): AddEditTxnEvent() data object UpsertTransaction: AddEditTxnEvent() diff --git a/app/src/main/java/com/suyash/creditmanager/presentation/add_edit_txn/AddEditTxnScreen.kt b/app/src/main/java/com/suyash/creditmanager/presentation/add_edit_txn/AddEditTxnScreen.kt index e9c8059..07e9924 100644 --- a/app/src/main/java/com/suyash/creditmanager/presentation/add_edit_txn/AddEditTxnScreen.kt +++ b/app/src/main/java/com/suyash/creditmanager/presentation/add_edit_txn/AddEditTxnScreen.kt @@ -116,6 +116,7 @@ fun AddEditTxnScreen( ) { var ccDropdownExpanded by remember { mutableStateOf(false) } var txnTypeDropdownExpanded by remember { mutableStateOf(false) } + var txnCategoryDropdownExpanded by remember { mutableStateOf(false) } ExposedDropdownMenuBox( modifier = Modifier.fillMaxWidth(), @@ -195,6 +196,45 @@ fun AddEditTxnScreen( } } Spacer(modifier = Modifier.height(16.dp)) + ExposedDropdownMenuBox( + modifier = Modifier.fillMaxWidth(), + expanded = txnCategoryDropdownExpanded, + onExpandedChange = { + txnCategoryDropdownExpanded = !txnCategoryDropdownExpanded + }) { + OutlinedTextField( + modifier = Modifier + .fillMaxWidth() + .menuAnchor(), + readOnly = true, + value = viewModel.txnCategory.value, + onValueChange = { }, + label = { Text("Transaction Category") }, + trailingIcon = { + ExposedDropdownMenuDefaults.TrailingIcon( + expanded = txnCategoryDropdownExpanded + ) + } + ) + ExposedDropdownMenu( + modifier = Modifier.fillMaxWidth(), + expanded = txnCategoryDropdownExpanded, + onDismissRequest = { + txnCategoryDropdownExpanded = false + } + ) { + viewModel.txnCategories.value.filter { it.type == viewModel.txnType.value }.forEach { + DropdownMenuItem( + text = { Text(text = it.name) }, + onClick = { + viewModel.onEvent(AddEditTxnEvent.SelectedTxnCategory(it.name)) + txnCategoryDropdownExpanded = false + } + ) + } + } + } + Spacer(modifier = Modifier.height(16.dp)) OutlinedTextField( modifier = Modifier .fillMaxWidth() diff --git a/app/src/main/java/com/suyash/creditmanager/presentation/add_edit_txn/AddEditTxnViewModel.kt b/app/src/main/java/com/suyash/creditmanager/presentation/add_edit_txn/AddEditTxnViewModel.kt index 2bae104..07fbb12 100644 --- a/app/src/main/java/com/suyash/creditmanager/presentation/add_edit_txn/AddEditTxnViewModel.kt +++ b/app/src/main/java/com/suyash/creditmanager/presentation/add_edit_txn/AddEditTxnViewModel.kt @@ -8,8 +8,10 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.suyash.creditmanager.domain.model.CreditCard import com.suyash.creditmanager.domain.model.Transaction +import com.suyash.creditmanager.domain.model.TxnCategory import com.suyash.creditmanager.domain.use_case.CreditCardUseCases import com.suyash.creditmanager.domain.use_case.TransactionUseCase +import com.suyash.creditmanager.domain.use_case.TxnCategoryUseCase import com.suyash.creditmanager.domain.util.CreditCardOrder import com.suyash.creditmanager.domain.util.OrderType import com.suyash.creditmanager.domain.util.TransactionType @@ -28,13 +30,18 @@ import javax.inject.Inject class AddEditTxnViewModel @Inject constructor( private val transactionUseCase: TransactionUseCase, private val creditCardUseCases: CreditCardUseCases, + private val txnCategoryUseCase: TxnCategoryUseCase, savedStateHandle: SavedStateHandle ): ViewModel() { private var getCreditCardsJob: Job? = null + private var getTxnCategoriesJob: Job? = null private val _creditCards = mutableStateOf(emptyList()) val creditCards: State> = _creditCards + private val _txnCategories = mutableStateOf(emptyList()) + val txnCategories: State> = _txnCategories + private val _dateFormatter = mutableStateOf(DateTimeFormatter.ofPattern("dd/MM/yyyy")) val dateFormatter: State = _dateFormatter @@ -44,6 +51,9 @@ class AddEditTxnViewModel @Inject constructor( private val _txnType = mutableStateOf(TransactionType.DEBIT) val txnType: State = _txnType + private val _txnCategory = mutableStateOf("") + val txnCategory: State = _txnCategory + private val _txnDate = mutableStateOf(LocalDate.now()) val txnDate: State = _txnDate @@ -57,13 +67,14 @@ class AddEditTxnViewModel @Inject constructor( val eventFlow = _eventFlow.asSharedFlow() init { - getCreditCards(CreditCardOrder.Name(OrderType.Ascending)) + getCreditCardsAndCategories(CreditCardOrder.Name(OrderType.Ascending)) savedStateHandle.get("txnId")?.let { txnId -> if(txnId != -1) { viewModelScope.launch { transactionUseCase.getTransaction(txnId)?.also { transaction -> _currentTxnId.intValue = transaction.id _txnType.value = transaction.type + _txnCategory.value = transaction.category?:"" _txnAmount.value = transaction.amount.toString() _selectedCreditCard.intValue = transaction.card _txnDate.value = transaction.date @@ -95,16 +106,20 @@ class AddEditTxnViewModel @Inject constructor( } is AddEditTxnEvent.SelectedTxnType -> { _txnType.value = event.value + _txnCategory.value = "" + } + is AddEditTxnEvent.SelectedTxnCategory -> { + _txnCategory.value = event.value } is AddEditTxnEvent.UpsertTransaction -> { viewModelScope.launch { transactionUseCase.upsertTransaction( Transaction( type = txnType.value, + category = txnCategory.value, amount = txnAmount.value.toFloatOrNull()?:0.0F, card = selectedCreditCard.value, date = txnDate.value, - category = null, id = currentTxnId.value ) ) @@ -119,11 +134,15 @@ class AddEditTxnViewModel @Inject constructor( } } - private fun getCreditCards(creditCardsOrder: CreditCardOrder) { + private fun getCreditCardsAndCategories(creditCardsOrder: CreditCardOrder) { getCreditCardsJob?.cancel() getCreditCardsJob = creditCardUseCases.getCreditCards(creditCardsOrder).onEach { creditCards -> _creditCards.value = creditCards }.launchIn(viewModelScope) + getTxnCategoriesJob?.cancel() + getTxnCategoriesJob = txnCategoryUseCase.getTxnCategories().onEach { txnCategories -> + _txnCategories.value = txnCategories + }.launchIn(viewModelScope) } fun getCCDisplay(): String { diff --git a/app/src/main/java/com/suyash/creditmanager/presentation/credit_cards/component/CreditCardItem.kt b/app/src/main/java/com/suyash/creditmanager/presentation/credit_cards/component/CreditCardItem.kt index 890419d..51821b5 100644 --- a/app/src/main/java/com/suyash/creditmanager/presentation/credit_cards/component/CreditCardItem.kt +++ b/app/src/main/java/com/suyash/creditmanager/presentation/credit_cards/component/CreditCardItem.kt @@ -29,7 +29,8 @@ fun CreditCardItem( ) { Column( modifier = modifier - .padding(16.dp) + .padding(horizontal = 16.dp) + .padding(vertical = 8.dp) ) { Row( modifier = Modifier.fillMaxWidth() diff --git a/app/src/main/java/com/suyash/creditmanager/presentation/emis/component/EMIItem.kt b/app/src/main/java/com/suyash/creditmanager/presentation/emis/component/EMIItem.kt index f9de020..e40322f 100644 --- a/app/src/main/java/com/suyash/creditmanager/presentation/emis/component/EMIItem.kt +++ b/app/src/main/java/com/suyash/creditmanager/presentation/emis/component/EMIItem.kt @@ -28,7 +28,8 @@ fun EMIItem( ) { Column( modifier = modifier - .padding(16.dp) + .padding(horizontal = 16.dp) + .padding(vertical = 8.dp) ) { Row( modifier = Modifier.fillMaxWidth() diff --git a/app/src/main/java/com/suyash/creditmanager/presentation/transactions/TransactionsScreen.kt b/app/src/main/java/com/suyash/creditmanager/presentation/transactions/TransactionsScreen.kt index 841cfc4..76c50f8 100644 --- a/app/src/main/java/com/suyash/creditmanager/presentation/transactions/TransactionsScreen.kt +++ b/app/src/main/java/com/suyash/creditmanager/presentation/transactions/TransactionsScreen.kt @@ -4,7 +4,6 @@ import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.combinedClickable -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth @@ -76,17 +75,15 @@ fun TransactionsScreen( val groupedTxn = viewModel.state.value.transactions.groupBy { it.date } groupedTxn.forEach { (date, transactions) -> stickyHeader { - Box(modifier = Modifier.padding(bottom = 16.dp)) { - Text( - text = date.format(viewModel.state.value.dateFormat.formatter), - fontSize = 16.sp, - fontWeight = FontWeight.Bold, - modifier = Modifier - .fillMaxWidth() - .background(MaterialTheme.colorScheme.primaryContainer) - .padding(horizontal = 16.dp) - ) - } + Text( + text = date.format(viewModel.state.value.dateFormat.formatter), + fontSize = 16.sp, + fontWeight = FontWeight.Bold, + modifier = Modifier + .fillMaxWidth() + .background(MaterialTheme.colorScheme.primaryContainer) + .padding(horizontal = 16.dp) + ) } items(transactions) { transaction -> TransactionItem( diff --git a/app/src/main/java/com/suyash/creditmanager/presentation/transactions/component/TransactionItem.kt b/app/src/main/java/com/suyash/creditmanager/presentation/transactions/component/TransactionItem.kt index 352658b..a4d2061 100644 --- a/app/src/main/java/com/suyash/creditmanager/presentation/transactions/component/TransactionItem.kt +++ b/app/src/main/java/com/suyash/creditmanager/presentation/transactions/component/TransactionItem.kt @@ -34,7 +34,7 @@ fun TransactionItem( Row( modifier = Modifier .fillMaxWidth() - .padding(bottom = 16.dp) + .padding(vertical = 8.dp) ) { Column( modifier = Modifier @@ -50,6 +50,10 @@ fun TransactionItem( style = MaterialTheme.typography.bodyLarge, color = if(transaction.type == TransactionType.DEBIT) DebitForeground else CreditForeground ) + Text( + text = transaction.category?:"", + style = MaterialTheme.typography.bodySmall, + ) } Spacer(modifier = Modifier.height(8.dp)) Row( @@ -57,7 +61,7 @@ fun TransactionItem( horizontalArrangement = Arrangement.SpaceBetween ) { Text( - text = creditCard?.cardName?:"Credit Card Name", + text = creditCard?.cardName?:"Deleted Credit Card", style = MaterialTheme.typography.bodySmall, ) Text(