/
BuildDashboardUseCase.kt
103 lines (96 loc) · 4.36 KB
/
BuildDashboardUseCase.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package serg.chuprin.finances.feature.dashboard.domain.usecase
import kotlinx.coroutines.flow.*
import serg.chuprin.finances.core.api.domain.model.User
import serg.chuprin.finances.core.api.domain.model.moneyaccount.query.MoneyAccountsQuery
import serg.chuprin.finances.core.api.domain.model.period.DataPeriod
import serg.chuprin.finances.core.api.domain.repository.MoneyAccountRepository
import serg.chuprin.finances.core.api.domain.repository.UserRepository
import serg.chuprin.finances.feature.dashboard.domain.builder.DashboardWidgetBuilder
import serg.chuprin.finances.feature.dashboard.domain.model.Dashboard
import serg.chuprin.finances.feature.dashboard.domain.model.DashboardWidgets
import serg.chuprin.finances.feature.dashboard.domain.repository.DashboardDataPeriodRepository
import serg.chuprin.finances.feature.dashboard.setup.domain.model.CustomizableDashboardWidget
import serg.chuprin.finances.feature.dashboard.setup.domain.model.DashboardWidgetType
import serg.chuprin.finances.feature.dashboard.setup.domain.repository.DashboardWidgetsRepository
import javax.inject.Inject
/**
* Created by Sergey Chuprin on 17.04.2020.
*/
class BuildDashboardUseCase @Inject constructor(
private val userRepository: UserRepository,
private val moneyAccountRepository: MoneyAccountRepository,
private val dataPeriodRepository: DashboardDataPeriodRepository,
private val dashboardWidgetsRepository: DashboardWidgetsRepository,
private val widgetBuilders: Set<@JvmSuppressWildcards DashboardWidgetBuilder<*>>
) {
fun execute(): Flow<Dashboard> {
return userRepository
.currentUserSingleFlow()
.flatMapLatest { user ->
combine(
flowOf(user),
moneyAccountRepository.accountsFlow(MoneyAccountsQuery(ownerId = user.id)),
::Pair
)
}
// Don't bother downstream with money account updates
// but only if new account created or all accounts deleted.
.distinctUntilChanged { (_, oldAccounts), (_, newAccounts) ->
oldAccounts.size == newAccounts.size
|| !(oldAccounts.isEmpty() || newAccounts.isEmpty())
}
.flatMapLatest { (user, moneyAccounts) ->
if (moneyAccounts.isEmpty()) {
flowOf(Dashboard(user = user, hasNoMoneyAccounts = true))
} else {
combine(
flowOf(user),
dataPeriodRepository
.currentDataPeriodFlow
.distinctUntilChanged(),
getOrderedWidgetsFlow(),
transform = ::Triple
).flatMapLatest { (currentUser, currentPeriod, orderedWidgets) ->
buildDashboard(currentUser, currentPeriod, orderedWidgets)
}
}
}
}
private fun buildDashboard(
currentUser: User,
currentPeriod: DataPeriod,
orderedWidgets: Map<DashboardWidgetType, Int>
): Flow<Dashboard> {
val flows = orderedWidgets.mapNotNull { (widgetType) ->
widgetBuilders
.firstOrNull { builder -> builder.isForType(widgetType) }
?.build(currentUser, currentPeriod)
}
return combine(flows) { flowsArray ->
flowsArray.fold(
initial = Dashboard(
user = currentUser,
hasNoMoneyAccounts = false,
currentDataPeriod = currentPeriod,
widgets = DashboardWidgets(orderedWidgets)
),
{ dashboard, widget ->
dashboard.copy(widgets = dashboard.widgets.put(widget))
}
)
}.debounce(100)
}
private fun getOrderedWidgetsFlow(): Flow<Map<DashboardWidgetType, Int>> {
return dashboardWidgetsRepository
.widgetsFlow
.map { widgets ->
widgets
.filter(CustomizableDashboardWidget::isEnabled)
.sortedBy(CustomizableDashboardWidget::order)
.mapIndexed { index, customizableDashboardWidget ->
customizableDashboardWidget.widgetType to index
}
.toMap()
}
}
}