@@ -4,15 +4,28 @@ import android.annotation.SuppressLint
4
4
import com.getcode.db.Database
5
5
import com.getcode.model.Currency
6
6
import com.getcode.model.CurrencyCode
7
+ import com.getcode.model.PrefsString
7
8
import com.getcode.model.Rate
8
9
import com.getcode.network.api.CurrencyApi
9
10
import com.getcode.network.core.NetworkOracle
11
+ import com.getcode.network.repository.PrefRepository
10
12
import com.getcode.utils.ErrorUtils
13
+ import com.getcode.utils.TraceType
14
+ import com.getcode.utils.trace
11
15
import kotlinx.coroutines.CoroutineScope
12
16
import kotlinx.coroutines.Dispatchers
13
17
import kotlinx.coroutines.flow.Flow
14
18
import kotlinx.coroutines.flow.MutableStateFlow
19
+ import kotlinx.coroutines.flow.combine
20
+ import kotlinx.coroutines.flow.distinctUntilChanged
15
21
import kotlinx.coroutines.flow.emptyFlow
22
+ import kotlinx.coroutines.flow.filterNotNull
23
+ import kotlinx.coroutines.flow.flatMapLatest
24
+ import kotlinx.coroutines.flow.flowOf
25
+ import kotlinx.coroutines.flow.launchIn
26
+ import kotlinx.coroutines.flow.map
27
+ import kotlinx.coroutines.flow.mapNotNull
28
+ import kotlinx.coroutines.flow.onEach
16
29
import kotlinx.coroutines.launch
17
30
import kotlinx.coroutines.suspendCancellableCoroutine
18
31
import timber.log.Timber
@@ -28,6 +41,8 @@ interface Exchange {
28
41
val localRate: Rate
29
42
fun observeLocalRate (): Flow <Rate >
30
43
44
+ val entryRate: Rate
45
+
31
46
fun rates (): Map <CurrencyCode , Rate >
32
47
fun observeRates (): Flow <Map <CurrencyCode , Rate >>
33
48
@@ -42,6 +57,9 @@ class ExchangeNull : Exchange {
42
57
override val localRate: Rate
43
58
get() = Rate .oneToOne
44
59
60
+ override val entryRate: Rate
61
+ get() = Rate .oneToOne
62
+
45
63
override fun observeLocalRate (): Flow <Rate > {
46
64
return emptyFlow()
47
65
}
@@ -69,12 +87,15 @@ class ExchangeNull : Exchange {
69
87
class CodeExchange @Inject constructor(
70
88
private val currencyApi : CurrencyApi ,
71
89
private val networkOracle : NetworkOracle ,
72
- private val defaultCurrency : () -> Currency ? ,
90
+ prefs : PrefRepository ,
91
+ private val defaultCurrency : suspend () -> Currency ? ,
73
92
) : Exchange, CoroutineScope by CoroutineScope(Dispatchers .IO ) {
74
93
75
94
private val db = Database .getInstance()
76
95
77
- private var entryRate: Rate = Rate .oneToOne
96
+ private var _entryRate : Rate = Rate .oneToOne
97
+ override val entryRate: Rate
98
+ get() = _entryRate
78
99
79
100
private val _localRate = MutableStateFlow (Rate .oneToOne)
80
101
override val localRate
@@ -116,6 +137,19 @@ class CodeExchange @Inject constructor(
116
137
117
138
fetchRatesIfNeeded()
118
139
}
140
+
141
+ prefs.observeOrDefault(PrefsString .KEY_PREFERRED_APP_CURRENCY , " " )
142
+ .map { it.takeIf { it.isNotEmpty() } }
143
+ .filterNotNull()
144
+ .mapNotNull { CurrencyCode .tryValueOf(it) }
145
+ .flatMapLatest {
146
+ combine(observeRates(), flowOf(it)) { rates, currencyCode -> rates[currencyCode] }
147
+ }.filterNotNull()
148
+ .distinctUntilChanged()
149
+ .onEach {
150
+ trace(" Local rate updated=${it.currency} " , type = TraceType .Log )
151
+ _localRate .value = it
152
+ }.launchIn(this )
119
153
}
120
154
121
155
override suspend fun fetchRatesIfNeeded () {
@@ -130,67 +164,71 @@ class CodeExchange @Inject constructor(
130
164
}
131
165
}
132
166
133
- private fun set (currency : CurrencyCode ) {
167
+ private suspend fun set (currency : CurrencyCode ) {
134
168
entryCurrency = currency
135
169
updateRates()
136
170
}
137
171
138
- private fun set (ratesBox : RatesBox ) {
172
+ private suspend fun set (ratesBox : RatesBox ) {
139
173
rates = ratesBox
140
174
rateDate = ratesBox.dateMillis
141
175
142
176
setLocalEntryCurrencyIfNeeded()
143
177
updateRates()
144
178
}
145
179
146
- private fun setLocalEntryCurrencyIfNeeded () {
147
- if (entryCurrency = = null ) {
180
+ private suspend fun setLocalEntryCurrencyIfNeeded () {
181
+ if (entryCurrency ! = null ) {
148
182
return
149
183
}
150
184
151
185
val localRegionCurrency = defaultCurrency() ? : return
152
-
153
- entryCurrency = CurrencyCode .tryValueOf(localRegionCurrency.code)
186
+ val currency = CurrencyCode .tryValueOf(localRegionCurrency.code)
187
+ entryCurrency = currency
154
188
}
155
189
156
190
override fun rateFor (currencyCode : CurrencyCode ): Rate ? = rates.rateFor(currencyCode)
157
191
158
192
override fun rateForUsd (): Rate ? = rates.rateForUsd()
159
193
160
- private fun updateRates () {
194
+ private suspend fun updateRates () {
161
195
if (rates.isEmpty) {
162
196
return
163
197
}
164
198
165
- val localCurrency = defaultCurrency()
199
+ val localCurrency = CurrencyCode .tryValueOf( defaultCurrency()?.code.orEmpty() )
166
200
val rate = localCurrency?.let { rates.rateFor(it) }
167
201
_localRate .value = if (rate != null ) {
168
- Timber .d(
169
- " Updated the entry currency: $localCurrency , Staleness ${System .currentTimeMillis() - rates.dateMillis} ms, Date: ${
170
- Date (
171
- rates.dateMillis
172
- )
173
- } "
202
+ trace(
203
+ message = " Updated the local currency: $localCurrency , " +
204
+ " Staleness ${System .currentTimeMillis() - rates.dateMillis} ms, " +
205
+ " Date: ${Date (rates.dateMillis)} " ,
206
+ type = TraceType .Silent
174
207
)
175
208
rate
176
209
} else {
177
- Timber .d(" Rate for $localCurrency not found. Defaulting to USD." )
210
+ trace(
211
+ message = " local:: Rate for $localCurrency not found. Defaulting to USD." ,
212
+ type = TraceType .Silent
213
+ )
178
214
rates.rateForUsd()!!
179
215
}
180
216
181
217
182
218
val entryRate = entryCurrency?.let { rates.rateFor(it) }
183
- this .entryRate = if (entryRate != null ) {
184
- Timber .d(
185
- " Updated the entry currency: $entryCurrency , Staleness ${System .currentTimeMillis() - rates.dateMillis} ms, Date: ${
186
- Date (
187
- rates.dateMillis
188
- )
189
- } "
219
+ this ._entryRate = if (entryRate != null ) {
220
+ trace(
221
+ message = " Updated the entry currency: $entryCurrency , " +
222
+ " Staleness ${System .currentTimeMillis() - rates.dateMillis} ms, " +
223
+ " Date: ${Date (rates.dateMillis)} " ,
224
+ type = TraceType .Silent
190
225
)
191
226
entryRate
192
227
} else {
193
- Timber .d(" Rate for $entryCurrency not found. Defaulting to USD." )
228
+ trace(
229
+ message = " entry:: Rate for $entryCurrency not found. Defaulting to USD." ,
230
+ type = TraceType .Silent
231
+ )
194
232
rates.rateForUsd()!!
195
233
}
196
234
0 commit comments