Skip to content

Commit

Permalink
Start budget detail screen
Browse files Browse the repository at this point in the history
  • Loading branch information
rodrigo-lm committed Jul 7, 2024
1 parent c60a4ea commit b92f5ca
Show file tree
Hide file tree
Showing 39 changed files with 739 additions and 365 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.rodrigolmti.lunch.money.companion.composition.bridge.adapter

import com.rodrigolmti.lunch.money.companion.composition.domain.repository.ILunchRepository
import com.rodrigolmti.lunch.money.companion.composition.domain.repository.IAppRepository
import com.rodrigolmti.lunch.money.companion.composition.domain.usecase.GetTransactionSumByCategoryUseCase
import com.rodrigolmti.lunch.money.companion.core.LunchError
import com.rodrigolmti.lunch.money.companion.core.Outcome
Expand All @@ -12,7 +12,7 @@ import java.util.Date

internal class AnalyzeFeatureAdapter(
val sumTransactionUseCase: GetTransactionSumByCategoryUseCase,
private val lunchRepository: ILunchRepository,
private val lunchRepository: IAppRepository,
) {

suspend fun getSumGroupedTransactions(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.rodrigolmti.lunch.money.companion.composition.bridge.adapter

import com.rodrigolmti.lunch.money.companion.composition.bridge.mapper.toView
import com.rodrigolmti.lunch.money.companion.composition.domain.repository.ILunchRepository
import com.rodrigolmti.lunch.money.companion.composition.domain.repository.IAppRepository
import com.rodrigolmti.lunch.money.companion.core.DEFAULT_CURRENCY
import com.rodrigolmti.lunch.money.companion.core.LunchError
import com.rodrigolmti.lunch.money.companion.core.Outcome
Expand All @@ -12,7 +12,7 @@ import java.util.Date

private const val CATEGORY_FILTER_KEY = "uncategorized"

internal class BudgetFeatureAdapter(private val lunchRepository: ILunchRepository) {
internal class BudgetFeatureAdapter(private val lunchRepository: IAppRepository) {

suspend fun getBudget(
start: Date,
Expand All @@ -26,4 +26,9 @@ internal class BudgetFeatureAdapter(private val lunchRepository: ILunchRepositor
}
}
}

fun getBudget(budgetId: Int): BudgetView? {
return lunchRepository.getBudgetById(budgetId)
?.toView(lunchRepository.getPrimaryCurrency() ?: DEFAULT_CURRENCY)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package com.rodrigolmti.lunch.money.companion.composition.bridge.adapter
import com.rodrigolmti.lunch.money.companion.composition.bridge.mapper.toView
import com.rodrigolmti.lunch.money.companion.composition.domain.model.AssetStatus
import com.rodrigolmti.lunch.money.companion.composition.domain.model.TransactionModel
import com.rodrigolmti.lunch.money.companion.composition.domain.repository.ILunchRepository
import com.rodrigolmti.lunch.money.companion.composition.domain.repository.IAppRepository
import com.rodrigolmti.lunch.money.companion.core.DEFAULT_CURRENCY
import com.rodrigolmti.lunch.money.companion.core.LunchError
import com.rodrigolmti.lunch.money.companion.core.Outcome
Expand All @@ -22,7 +22,7 @@ import kotlinx.collections.immutable.toImmutableList
import java.util.Date

internal class HomeFeatureAdapter(
private val lunchRepository: ILunchRepository,
private val lunchRepository: IAppRepository,
) {

suspend fun getAssetOverview(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package com.rodrigolmti.lunch.money.companion.composition.bridge.adapter

import com.rodrigolmti.lunch.money.companion.composition.bridge.mapper.toView
import com.rodrigolmti.lunch.money.companion.composition.domain.repository.ILunchRepository
import com.rodrigolmti.lunch.money.companion.composition.domain.repository.IAppRepository
import com.rodrigolmti.lunch.money.companion.core.LunchError
import com.rodrigolmti.lunch.money.companion.core.Outcome
import com.rodrigolmti.lunch.money.companion.core.map
import com.rodrigolmti.lunch.money.companion.features.recurring.RecurringView

internal class RecurringFeatureAdapter(private val lunchRepository: ILunchRepository) {
internal class RecurringFeatureAdapter(private val lunchRepository: IAppRepository) {

suspend fun getRecurring(): Outcome<List<RecurringView>, LunchError> {
return lunchRepository.getRecurring().map { response ->
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package com.rodrigolmti.lunch.money.companion.composition.bridge.adapter

import com.rodrigolmti.lunch.money.companion.composition.bridge.mapper.toView
import com.rodrigolmti.lunch.money.companion.composition.domain.repository.ILunchRepository
import com.rodrigolmti.lunch.money.companion.composition.domain.repository.IAppRepository
import com.rodrigolmti.lunch.money.companion.core.DEFAULT_CURRENCY
import com.rodrigolmti.lunch.money.companion.core.LunchError
import com.rodrigolmti.lunch.money.companion.core.Outcome
import com.rodrigolmti.lunch.money.companion.features.settings.model.SettingsView

internal class SettingsFeatureAdapter(private val lunchRepository: ILunchRepository) {
internal class SettingsFeatureAdapter(private val lunchRepository: IAppRepository) {

fun getUserData(): Outcome<SettingsView, LunchError> {
lunchRepository.getSessionUser()?.let { user ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package com.rodrigolmti.lunch.money.companion.composition.bridge.adapter

import com.rodrigolmti.lunch.money.companion.composition.bridge.mapper.toDto
import com.rodrigolmti.lunch.money.companion.composition.bridge.mapper.toView
import com.rodrigolmti.lunch.money.companion.composition.domain.repository.ILunchRepository
import com.rodrigolmti.lunch.money.companion.composition.domain.repository.IAppRepository
import com.rodrigolmti.lunch.money.companion.core.DEFAULT_CURRENCY
import com.rodrigolmti.lunch.money.companion.core.LunchError
import com.rodrigolmti.lunch.money.companion.core.Outcome
Expand All @@ -15,7 +15,7 @@ import com.rodrigolmti.lunch.money.companion.features.transactions.ui.summary.Tr
import java.util.Date

internal class TransactionFeatureAdapter(
private val lunchRepository: ILunchRepository
private val lunchRepository: IAppRepository
) {

suspend fun getTransactionSummary(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
package com.rodrigolmti.lunch.money.companion.composition.bridge.mapper

import com.rodrigolmti.lunch.money.companion.composition.domain.model.BudgetModel
import com.rodrigolmti.lunch.money.companion.composition.domain.model.CategoryModel
import com.rodrigolmti.lunch.money.companion.features.budget.BudgetItemView
import com.rodrigolmti.lunch.money.companion.features.budget.BudgetView

internal fun BudgetModel.toView(currency: String): BudgetView {
return BudgetView(
category = categoryName,
items = data.map {
BudgetItemView(
totalTransactions = it.numTransactions,
totalSpending = it.spendingToBase,
totalBudget = it.budgetAmount,
currency = it.budgetCurrency ?: currency,
)
}
items = data.mapValues {
it.value.toView(currency)
},
)
}

internal fun CategoryModel.toView(currency: String): BudgetItemView {
return BudgetItemView(
totalTransactions = numTransactions,
totalSpending = spendingToBase,
totalBudget = budgetToBase,
currency = currency,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,44 +6,49 @@ import com.rodrigolmti.lunch.money.companion.composition.data.model.response.Cat
import com.rodrigolmti.lunch.money.companion.composition.data.model.response.CategoryResponse
import com.rodrigolmti.lunch.money.companion.composition.domain.model.BudgetModel
import com.rodrigolmti.lunch.money.companion.composition.domain.model.BudgetRecurringModel
import com.rodrigolmti.lunch.money.companion.composition.domain.model.CategoryModel
import com.rodrigolmti.lunch.money.companion.composition.domain.model.CategoryConfigModel
import com.rodrigolmti.lunch.money.companion.composition.domain.model.CategoryModel

internal fun mapBudget(budgets: List<BudgetResponse>): List<BudgetModel> {
return budgets.map {
it.toModel()
}
}

internal fun BudgetResponse.toModel() = BudgetModel(
categoryName = categoryName,
categoryId = categoryId,
categoryGroupName = categoryGroupName,
groupId = groupId,
isGroup = isGroup ?: false,
isIncome = isIncome,
excludeFromBudget = excludeFromBudget,
excludeFromTotals = excludeFromTotals,
data = data.map { it.value?.toModel(it.key) }.filterNotNull(),
config = config?.toModel(),
order = order,
recurring = recurring?.list?.map { it.toModel() } ?: emptyList(),
)
internal fun BudgetResponse.toModel(): BudgetModel {
val data: Map<String, CategoryModel> = data
.filter { it.value != null }
.mapValues { it.value!!.toModel() }

return BudgetModel(
categoryName = categoryName,
categoryId = categoryId,
categoryGroupName = categoryGroupName,
groupId = groupId,
isGroup = isGroup ?: false,
isIncome = isIncome,
excludeFromBudget = excludeFromBudget,
excludeFromTotals = excludeFromTotals,
data = data,
config = config?.toModel(),
order = order,
recurring = recurring?.list?.map { it.toModel() } ?: emptyList(),
)
}

internal fun BudgetRecurringResponse.toModel() = BudgetRecurringModel(
payee = payee,
amount = amount,
currency = currency,
)

internal fun CategoryResponse.toModel(date: String) = CategoryModel(
internal fun CategoryResponse.toModel() = CategoryModel(
numTransactions = numTransactions ?: 0,
spendingToBase = spendingToBase ?: 0.0f,
budgetToBase = budgetToBase ?: 0.0f,
budgetAmount = budgetAmount ?: 0.0f,
budgetCurrency = budgetCurrency,
isAutomated = isAutomated ?: false,
date = date,
)

internal fun CategoryConfigResponse.toModel() = CategoryConfigModel(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import com.rodrigolmti.lunch.money.companion.composition.domain.model.RecurringM
import com.rodrigolmti.lunch.money.companion.composition.domain.model.TransactionCategoryModel
import com.rodrigolmti.lunch.money.companion.composition.domain.model.TransactionModel
import com.rodrigolmti.lunch.money.companion.composition.domain.model.UserModel
import com.rodrigolmti.lunch.money.companion.composition.domain.repository.ILunchRepository
import com.rodrigolmti.lunch.money.companion.composition.domain.repository.IAppRepository
import com.rodrigolmti.lunch.money.companion.core.ConnectionChecker
import com.rodrigolmti.lunch.money.companion.core.DEFAULT_EMPTY_STRING
import com.rodrigolmti.lunch.money.companion.core.IDispatchersProvider
Expand All @@ -42,16 +42,17 @@ private const val CURRENCY_KEY = "currency_key"
private const val CATEGORIES_CACHE = "categories_cache"
private const val ASSET_CACHE = "asset_cache"
private const val TRANSACTION_CACHE = "transaction_cache"
private const val BUDGET_CACHE = "budget_cache"

internal class LunchRepository(
internal class AppRepository(
private val json: Json,
private val lunchService: LunchService,
cacheManager: ICacheManager,
private val connectionChecker: ConnectionChecker,
private val dispatchers: IDispatchersProvider,
private val preferences: SharedPreferencesDelegateFactory,
private val iCrashlyticsSdk: ICrashlyticsSdk,
) : ILunchRepository {
) : IAppRepository {

private var user: String by preferences.create(DEFAULT_EMPTY_STRING, USER_KEY)
private var token: String by preferences.create(DEFAULT_EMPTY_STRING, TOKEN_KEY)
Expand All @@ -65,15 +66,16 @@ internal class LunchRepository(
private val assetCache = cacheManager.createCache<String, List<AssetModel>>(ASSET_CACHE)
private val transactionCache =
cacheManager.createCache<String, TransactionModel>(TRANSACTION_CACHE)
private val budgetCache = cacheManager.createCache<String, List<BudgetModel>>(BUDGET_CACHE)

override suspend fun authenticateUser(tokenDTO: TokenDTO): Outcome<Unit, LunchError> {
if (!connectionChecker.isConnected()) return Outcome.failure(LunchError.NoConnectionError)

return withContext(dispatchers.io()) {
runCatching {
val userResponse = lunchService.getUser(tokenDTO.format())
this@LunchRepository.token = tokenDTO.value
this@LunchRepository.user = json
this@AppRepository.token = tokenDTO.value
this@AppRepository.user = json
.encodeToString(UserResponse.serializer(), userResponse)
}.mapThrowable {
handleNetworkError(it)
Expand All @@ -87,6 +89,8 @@ internal class LunchRepository(
categoriesCache.clear()
transactionCache.clear()
assetCache.clear()
budgetCache.clear()
Unit
}.mapThrowable {
iCrashlyticsSdk.logNonFatal(it)
LunchError.UnsuccessfulLogoutError
Expand Down Expand Up @@ -163,13 +167,17 @@ internal class LunchRepository(
}
}

override fun getBudgetById(id: Int): BudgetModel? {
return budgetCache.get(BUDGET_CACHE, emptyList()).find { it.categoryId == id }
}

override fun getAssets(): List<AssetModel> = assetCache.get(ASSET_CACHE, emptyList())

override suspend fun cacheTransactionCategories() {
withContext(dispatchers.io()) {
val categories = lunchService.getCategories().categories.map { it.toModel() }
categoriesCache.clear()
categoriesCache.put(CATEGORIES_CACHE, categories)
.put(CATEGORIES_CACHE, categories)
}
}

Expand All @@ -178,8 +186,9 @@ internal class LunchRepository(
val assets = lunchService.getAssets().assets.map { it.toModel() }
val plaidAccounts = lunchService.getPlaidAccounts().accounts.map { it.toModel() }
val crypto = lunchService.getCrypto().crypto.map { it.toModel() }
assetCache.clear()
assetCache.put(ASSET_CACHE, assets + plaidAccounts + crypto)
assetCache
.clear()
.put(ASSET_CACHE, assets + plaidAccounts + crypto)
}
}

Expand All @@ -192,6 +201,9 @@ internal class LunchRepository(
return withContext(dispatchers.io()) {
runCatching {
val response = lunchService.getBudgets(start, end)
budgetCache
.clear()
.put(BUDGET_CACHE, mapBudget(response))
mapBudget(response)
}.mapThrowable {
handleNetworkError(it)
Expand Down
Loading

0 comments on commit b92f5ca

Please sign in to comment.