-
-
Notifications
You must be signed in to change notification settings - Fork 79
/
DefaultCounterComponent.kt
117 lines (98 loc) · 3.72 KB
/
DefaultCounterComponent.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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package com.arkivanov.sample.shared.counters.counter
import com.arkivanov.decompose.ComponentContext
import com.arkivanov.decompose.router.slot.ChildSlot
import com.arkivanov.decompose.router.slot.SlotNavigation
import com.arkivanov.decompose.router.slot.activate
import com.arkivanov.decompose.router.slot.childSlot
import com.arkivanov.decompose.router.slot.dismiss
import com.arkivanov.decompose.value.MutableValue
import com.arkivanov.decompose.value.Value
import com.arkivanov.decompose.value.operator.map
import com.arkivanov.decompose.value.update
import com.arkivanov.essenty.instancekeeper.InstanceKeeper
import com.arkivanov.essenty.instancekeeper.getOrCreate
import com.arkivanov.sample.shared.counters.counter.CounterComponent.Model
import com.arkivanov.sample.shared.dialog.DefaultDialogComponent
import com.arkivanov.sample.shared.dialog.DialogComponent
import com.badoo.reaktive.disposable.scope.DisposableScope
import com.badoo.reaktive.observable.observableInterval
import com.badoo.reaktive.scheduler.Scheduler
import com.badoo.reaktive.scheduler.mainScheduler
import kotlinx.serialization.Serializable
internal class DefaultCounterComponent(
componentContext: ComponentContext,
private val title: String,
private val isBackEnabled: Boolean,
private val onNext: () -> Unit,
private val onPrev: () -> Unit,
tickScheduler: Scheduler = mainScheduler,
) : CounterComponent, ComponentContext by componentContext {
private val handler =
instanceKeeper.getOrCreate(KEY_STATE) {
Handler(
initialState = stateKeeper.consume(key = KEY_STATE, strategy = State.serializer()) ?: State(),
tickScheduler = tickScheduler,
)
}
override val model: Value<Model> = handler.state.map { it.toModel() }
private val dialogNavigation = SlotNavigation<DialogConfig>()
private val _dialogSlot =
childSlot(
source = dialogNavigation,
serializer = null,
handleBackButton = true,
childFactory = { config, _ ->
DefaultDialogComponent(
title = "Counter",
message = "Value: ${formatCount(config.count)}",
onDismissed = dialogNavigation::dismiss,
)
}
)
override val dialogSlot: Value<ChildSlot<*, DialogComponent>> = _dialogSlot
override fun onInfoClicked() {
dialogNavigation.activate(DialogConfig(count = handler.state.value.count))
}
init {
stateKeeper.register(key = KEY_STATE, strategy = State.serializer()) { handler.state.value }
}
private fun State.toModel(): Model =
Model(
title = title,
text = formatCount(count),
isBackEnabled = isBackEnabled,
)
private fun formatCount(count: Int): String =
count.toString().padStart(length = 3, padChar = '0')
override fun onNextClicked() {
onNext()
}
override fun onPrevClicked() {
onPrev()
}
private companion object {
private const val KEY_STATE = "STATE"
}
@Serializable
private data class State(
val count: Int = 0,
)
@Serializable
private data class DialogConfig(
val count: Int,
)
private class Handler(
initialState: State,
tickScheduler: Scheduler,
) : InstanceKeeper.Instance, DisposableScope by DisposableScope() {
val state: MutableValue<State> = MutableValue(initialState)
init {
observableInterval(periodMillis = 250L, scheduler = tickScheduler).subscribeScoped {
state.update { it.copy(count = it.count + 1) }
}
}
override fun onDestroy() {
dispose()
}
}
}