Skip to content
This repository has been archived by the owner on Nov 5, 2024. It is now read-only.

Commit

Permalink
ReportsScreen: Improvements & BugFixes
Browse files Browse the repository at this point in the history
  • Loading branch information
Vishwa-Raghavendra committed May 11, 2022
1 parent 65ffba3 commit dd5aff7
Show file tree
Hide file tree
Showing 9 changed files with 108 additions and 90 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,16 @@ object WalletValueFunctions {
): BigDecimal = with(transaction) {
val condition = arg.accounts.any { it.id == this.toAccountId }
when {
type == TransactionType.TRANSFER && condition -> exchangeInBaseCurrency(
transaction = this.copy(amount = this.toAmount),
accounts = arg.accounts,
baseCurrency = arg.baseCurrency,
exchange = arg.exchange
)
type == TransactionType.TRANSFER && condition ->
exchangeInBaseCurrency(
transaction = this.copy(
amount = this.toAmount,
accountId = this.toAccountId ?: this.accountId
), //Do not remove copy()
accounts = arg.accounts,
baseCurrency = arg.baseCurrency,
exchange = arg.exchange
)
else -> BigDecimal.ZERO
}
}
Expand Down
3 changes: 2 additions & 1 deletion app/src/main/java/com/ivy/wallet/ui/Screens.kt
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ data class PieChartStatistic(
val type: TransactionType,
val filterExcluded: Boolean = true,
val accountList: List<UUID> = emptyList(),
val transactions: List<Transaction> = emptyList()
val transactions: List<Transaction> = emptyList(),
val treatTransfersAsIncomeExpense: Boolean = false
) : Screen

data class EditPlanned(
Expand Down
23 changes: 19 additions & 4 deletions app/src/main/java/com/ivy/wallet/ui/reports/ReportScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import com.google.accompanist.insets.systemBarsPadding
import com.ivy.design.api.navigation
import com.ivy.design.l0_system.UI
import androidx.compose.ui.res.stringResource
import com.ivy.design.l0_system.style
import com.ivy.wallet.R
import com.ivy.wallet.domain.data.TransactionType
Expand Down Expand Up @@ -152,7 +151,8 @@ private fun BoxWithConstraintsScope.UI(
PieChartStatistic(
type = TransactionType.INCOME,
transactions = state.transactions,
accountList = state.accountIdFilters
accountList = state.accountIdFilters,
treatTransfersAsIncomeExpense = state.treatTransfersAsIncExp
)
)
},
Expand All @@ -162,13 +162,28 @@ private fun BoxWithConstraintsScope.UI(
PieChartStatistic(
type = TransactionType.EXPENSE,
transactions = state.transactions,
accountList = state.accountIdFilters
accountList = state.accountIdFilters,
treatTransfersAsIncomeExpense = state.treatTransfersAsIncExp
)
)
}
)

Spacer(Modifier.height(32.dp))
if (state.showTransfersAsIncExpCheckbox) {
IvyCheckboxWithText(
modifier = Modifier
.padding(16.dp),
text = stringResource(R.string.transfers_as_income_expense),
checked = state.treatTransfersAsIncExp
) {
onEventHandler.invoke(
ReportScreenEvent.OnTreatTransfersAsIncomeExpense(
transfersAsIncomeExpense = it
)
)
}
} else
Spacer(Modifier.height(32.dp))

TransactionsDividerLine(
paddingHorizontal = 0.dp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ sealed class ReportScreenEvent {
data class OnUpcomingExpanded(val upcomingExpanded: Boolean) : ReportScreenEvent()
data class OnOverdueExpanded(val overdueExpanded: Boolean) : ReportScreenEvent()
data class OnFilterOverlayVisible(val filterOverlayVisible: Boolean) : ReportScreenEvent()
data class OnTreatTransfersAsIncomeExpense(val transfersAsIncomeExpense: Boolean) :
ReportScreenEvent()
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,7 @@ data class ReportScreenState(
val loading: Boolean = false,
val accountIdFilters: List<UUID> = emptyList(),
val transactions: List<Transaction> = emptyList(),
val filterOverlayVisible: Boolean = false
val filterOverlayVisible: Boolean = false,
val showTransfersAsIncExpCheckbox: Boolean = false,
val treatTransfersAsIncExp: Boolean = false
)
114 changes: 44 additions & 70 deletions app/src/main/java/com/ivy/wallet/ui/reports/ReportViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.ivy.design.navigation.Navigation
import com.ivy.fp.filterSuspend
import com.ivy.fp.sumOfSuspend
import com.ivy.fp.viewmodel.IvyViewModel
import com.ivy.fp.viewmodel.readOnly
import com.ivy.wallet.R
import com.ivy.wallet.domain.action.account.AccountsAct
import com.ivy.wallet.domain.action.category.CategoriesAct
Expand All @@ -21,6 +21,7 @@ import com.ivy.wallet.domain.data.core.Category
import com.ivy.wallet.domain.data.core.Transaction
import com.ivy.wallet.domain.deprecated.logic.PlannedPaymentsLogic
import com.ivy.wallet.domain.deprecated.logic.csv.ExportCSVLogic
import com.ivy.wallet.domain.pure.data.IncomeExpenseTransferPair
import com.ivy.wallet.domain.pure.exchange.ExchangeData
import com.ivy.wallet.domain.pure.transaction.trnCurrency
import com.ivy.wallet.domain.pure.util.orZero
Expand All @@ -38,6 +39,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
import java.math.BigDecimal
import javax.inject.Inject

@HiltViewModel
Expand Down Expand Up @@ -67,26 +69,28 @@ class ReportViewModel @Inject constructor(
private val _categories = MutableStateFlow<List<Category>>(emptyList())
val categories = _categories.readOnly()

private val _accounts = MutableStateFlow<List<Account>>(emptyList())
val accounts = _accounts.readOnly()
private val _allAccounts = MutableStateFlow<List<Account>>(emptyList())

private val _baseCurrency = MutableStateFlow("")
val baseCurrency = _baseCurrency.readOnly()

private val _historyIncomeExpense = MutableStateFlow(IncomeExpenseTransferPair.zero())
private val historyIncomeExpense = _historyIncomeExpense.readOnly()

private val _filter = MutableStateFlow<ReportFilter?>(null)
val filter = _filter.readOnly()

fun start() {
viewModelScope.launch(Dispatchers.IO) {
_baseCurrency.value = baseCurrencyAct(Unit)
_accounts.value = accountsAct(Unit)
_allAccounts.value = accountsAct(Unit)
_categories.value = listOf(unSpecifiedCategory) + categoriesAct(Unit)

updateState {
it.copy(
baseCurrency = _baseCurrency.value,
categories = _categories.value,
accounts = _accounts.value
accounts = _allAccounts.value
)
}
}
Expand All @@ -101,7 +105,7 @@ class ReportViewModel @Inject constructor(
}

if (!filter.validate()) return@scopedIOThread
val accounts = accounts.value
val accounts = filter.accounts
val baseCurrency = baseCurrency.value
_filter.value = filter

Expand All @@ -128,24 +132,21 @@ class ReportViewModel @Inject constructor(
)
}

val historyIncomeExpense = calcTrnsIncomeExpenseAct(
_historyIncomeExpense.value = calcTrnsIncomeExpenseAct(
CalcTrnsIncomeExpenseAct.Input(
transactions = history,
accounts = accounts,
baseCurrency = baseCurrency
)
)

val balance = scope.async {
calculateBalance(
baseCurrency = baseCurrency,
accounts = accounts,
history = history,
income = historyIncomeExpense.income.toDouble(),
expenses = historyIncomeExpense.expense.toDouble(),
filter = filter
)
}
val income = historyIncomeExpense.value.income.toDouble() +
if (stateVal().treatTransfersAsIncExp) historyIncomeExpense.value.transferIncome.toDouble() else 0.0

val expenses = historyIncomeExpense.value.expense.toDouble() +
if (stateVal().treatTransfersAsIncExp) historyIncomeExpense.value.transferExpense.toDouble() else 0.0

val balance = calculateBalance(historyIncomeExpense.value).toDouble()

val accountFilterIdList = scope.async { filter.accounts.map { it.id } }

Expand Down Expand Up @@ -181,8 +182,8 @@ class ReportViewModel @Inject constructor(

updateState {
it.copy(
income = historyIncomeExpense.income.toDouble(),
expenses = historyIncomeExpense.expense.toDouble(),
income = income,
expenses = expenses,
upcomingIncome = upcomingIncomeExpense.income.toDouble(),
upcomingExpenses = upcomingIncomeExpense.expense.toDouble(),
overdueIncome = overdueIncomeExpense.income.toDouble(),
Expand All @@ -191,13 +192,14 @@ class ReportViewModel @Inject constructor(
upcomingTransactions = upcomingTransactions,
overdueTransactions = overdue,
categories = categories.value,
accounts = _accounts.value,
accounts = _allAccounts.value,
filter = filter,
loading = false,
accountIdFilters = accountFilterIdList.await(),
transactions = transactions,
balance = balance.await(),
filterOverlayVisible = false
balance = balance,
filterOverlayVisible = false,
showTransfersAsIncExpCheckbox = filter.trnTypes.contains(TransactionType.TRANSFER)
)
}
}
Expand Down Expand Up @@ -311,53 +313,8 @@ class ReportViewModel @Inject constructor(
return this.toLowerCaseLocal().contains(anotherString.toLowerCaseLocal())
}

private suspend fun calculateBalance(
baseCurrency: String,
accounts: List<Account>,
history: List<Transaction>,
income: Double,
expenses: Double,
filter: ReportFilter
): Double {
val includedAccountsIds = filter.accounts.map { it.id }
//+ Transfers In (#conv to BaseCurrency)
val transfersIn = history
.filter {
it.type == TransactionType.TRANSFER &&
it.toAccountId != null && includedAccountsIds.contains(it.toAccountId)
}
.sumOfSuspend { trn ->
exchangeAct(
ExchangeAct.Input(
data = ExchangeData(
baseCurrency = baseCurrency,
fromCurrency = trnCurrency(trn, accounts, baseCurrency),
),
amount = trn.amount
)
).orZero().toDouble()
}

//- Transfers Out (#conv to BaseCurrency)
val transfersOut = history
.filter {
it.type == TransactionType.TRANSFER &&
includedAccountsIds.contains(it.accountId)
}
.sumOfSuspend { trn ->
exchangeAct(
ExchangeAct.Input(
data = ExchangeData(
baseCurrency = baseCurrency,
fromCurrency = trnCurrency(trn, accounts, baseCurrency),
),
amount = trn.amount
)
).orZero().toDouble()
}

//Income - Expenses (#conv to BaseCurrency)
return income - expenses + transfersIn - transfersOut
private fun calculateBalance(incomeExpenseTransferPair: IncomeExpenseTransferPair) : BigDecimal{
return incomeExpenseTransferPair.income + incomeExpenseTransferPair.transferIncome - incomeExpenseTransferPair.expense - incomeExpenseTransferPair.transferExpense
}

private suspend fun export(context: Context) {
Expand All @@ -367,7 +324,7 @@ class ReportViewModel @Inject constructor(
) {
val filter = _filter.value ?: return@protectWithPaywall
if (!filter.validate()) return@protectWithPaywall
val accounts = _accounts.value
val accounts = _allAccounts.value
val baseCurrency = _baseCurrency.value

ivyContext.createNewFile(
Expand Down Expand Up @@ -430,6 +387,20 @@ class ReportViewModel @Inject constructor(
}
}

private suspend fun onTreatTransfersAsIncomeExpense(treatTransfersAsIncExp: Boolean) {
updateState {
val income = historyIncomeExpense.value.income.toDouble() +
if (treatTransfersAsIncExp) historyIncomeExpense.value.transferIncome.toDouble() else 0.0
val expenses = historyIncomeExpense.value.expense.toDouble() +
if (treatTransfersAsIncExp) historyIncomeExpense.value.transferExpense.toDouble() else 0.0
it.copy(
treatTransfersAsIncExp = treatTransfersAsIncExp,
income = income,
expenses = expenses
)
}
}

fun onEvent(event: ReportScreenEvent) {
viewModelScope.launch(Dispatchers.Default) {
when (event) {
Expand All @@ -439,6 +410,9 @@ class ReportViewModel @Inject constructor(
is ReportScreenEvent.OnOverdueExpanded -> setOverdueExpanded(event.overdueExpanded)
is ReportScreenEvent.OnUpcomingExpanded -> setUpcomingExpanded(event.upcomingExpanded)
is ReportScreenEvent.OnFilterOverlayVisible -> setFilterOverlayVisible(event.filterOverlayVisible)
is ReportScreenEvent.OnTreatTransfersAsIncomeExpense -> onTreatTransfersAsIncomeExpense(
event.transfersAsIncomeExpense
)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import com.ivy.wallet.ui.onboarding.model.TimePeriod
import com.ivy.wallet.ui.theme.modal.ChoosePeriodModalData
import com.ivy.wallet.utils.dateNowUTC
import com.ivy.wallet.utils.ioThread
import com.ivy.wallet.utils.readOnly
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
Expand All @@ -33,6 +34,9 @@ class PieChartStatisticViewModel @Inject constructor(
PieChartStatisticState()
)

private val _treatTransfersAsIncomeExpense = MutableStateFlow(false)
private val treatTransfersAsIncomeExpense = _treatTransfersAsIncomeExpense.readOnly()

fun start(
screen: PieChartStatistic
) {
Expand All @@ -42,7 +46,8 @@ class PieChartStatisticViewModel @Inject constructor(
type = screen.type,
accountIdFilterList = screen.accountList,
filterExclude = screen.filterExcluded,
transactions = screen.transactions
transactions = screen.transactions,
treatTransfersAsIncomeExpense = screen.treatTransfersAsIncomeExpense
)
}
}
Expand All @@ -52,9 +57,11 @@ class PieChartStatisticViewModel @Inject constructor(
type: TransactionType,
accountIdFilterList: List<UUID>,
filterExclude: Boolean,
transactions: List<Transaction>
transactions: List<Transaction>,
treatTransfersAsIncomeExpense: Boolean
) {
initialise(period, type, accountIdFilterList, filterExclude, transactions)
_treatTransfersAsIncomeExpense.value = treatTransfersAsIncomeExpense
load(period = period)
}

Expand Down Expand Up @@ -90,12 +97,11 @@ class PieChartStatisticViewModel @Inject constructor(
val baseCurrency = stateVal().baseCurrency
val range = period.toRange(ivyContext.startDayOfMonth)

//transactions.isEmpty() condition disables treating transfers as income/expenses in Reports Screen
val treatTransferAsIncExp =
sharedPrefs.getBoolean(
SharedPrefs.TRANSFERS_AS_INCOME_EXPENSE,
false
) && accountIdFilterList.isNotEmpty() && transactions.isEmpty()
) && accountIdFilterList.isNotEmpty() && treatTransfersAsIncomeExpense.value

val pieChartActOutput = ioThread {
pieChartAct(
Expand Down
Loading

0 comments on commit dd5aff7

Please sign in to comment.