Coverage Summary for Class: GetActiveBudgetProgressUseCase (com.georgeci.moneysurfer.domain.usecase)
| Class |
Method, %
|
Branch, %
|
Line, %
|
Instruction, %
|
| GetActiveBudgetProgressUseCase |
100%
(4/4)
|
100%
(4/4)
|
100%
(13/13)
|
100%
(23/23)
|
| GetActiveBudgetProgressUseCase$invoke$$inlined$flatMapLatest$1 |
0%
(0/1)
|
|
| GetActiveBudgetProgressUseCase$invoke$$inlined$map$1 |
0%
(0/2)
|
|
| GetActiveBudgetProgressUseCase$invoke$$inlined$map$1$1 |
|
| GetActiveBudgetProgressUseCase$invoke$$inlined$map$1$2 |
0%
(0/1)
|
|
| GetActiveBudgetProgressUseCase$invoke$$inlined$map$1$2$1 |
|
| Total |
50%
(4/8)
|
100%
(4/4)
|
100%
(13/13)
|
100%
(23/23)
|
package com.georgeci.moneysurfer.domain.usecase
import com.georgeci.moneysurfer.domain.model.BudgetProgress
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.datetime.TimeZone
import org.koin.core.annotation.Single
/**
* Live progress for every budget the user is still tracking, empty while nothing backs one — no
* workspace, no budgets, or a workspace whose budgets were all archived.
*
* Archived budgets are dropped before progress is computed rather than after: progress reads the
* whole transaction list per budget, and a workspace can accumulate archived budgets indefinitely.
*
* The workspace comes from the budgets themselves rather than from a second subscription to
* `SessionPointers.currentWorkspaceId`. Two collectors of the same pointer are not ordered against
* each other, so on a workspace switch the budget query can deliver the new workspace's budgets
* while the separately-read id is still the old one — and `progressOf` would then match those
* budgets against the previous workspace's transactions, briefly reporting the full limit as
* unspent. Reading both from one emission makes that pairing impossible; [GetBudgetsUseCase]
* already returns an empty list when nobody is signed in, which is the same "nothing to show"
* answer.
*/
@Single
@OptIn(ExperimentalCoroutinesApi::class)
class GetActiveBudgetProgressUseCase(
private val getBudgets: GetBudgetsUseCase,
private val getBudgetProgress: GetBudgetProgressUseCase,
) {
operator fun invoke(
timeZone: TimeZone = TimeZone.currentSystemDefault(),
): Flow<List<BudgetProgress>> =
getBudgets()
.map { budgets -> budgets.filter { it.isActive } }
.distinctUntilChanged()
.flatMapLatest { budgets ->
val workspaceId = budgets.firstOrNull()?.workspaceId
if (workspaceId == null) {
flowOf(emptyList())
} else {
getBudgetProgress.progressOf(workspaceId, budgets, timeZone)
}
}
}