Skip to content

Commit 7e53605

Browse files
committed
feat: update balance currency to rescope app currency
Signed-off-by: Brandon McAnsh <[email protected]>
1 parent fb99c9d commit 7e53605

File tree

9 files changed

+116
-106
lines changed

9 files changed

+116
-106
lines changed

api/src/main/java/com/getcode/model/PrefString.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ data class PrefString(
1212
enum class PrefsString(val value: String) {
1313
KEY_USER_ID("user_id"),
1414
KEY_DATA_CONTAINER_ID("data_container_id"),
15-
KEY_CURRENCY_SELECTED("currency_selected"),//keep
15+
KEY_GIVE_CURRENCY_SELECTED("currency_selected"),//keep
1616
KEY_CURRENCIES_RECENT("currencies_recent"),//keep
1717
KEY_TIP_ACCOUNT("tip_account"),
18-
KEY_BALANCE_CURRENCY_SELECTED("balance_currency_selected"),//keep
18+
KEY_PREFERRED_APP_CURRENCY("balance_currency_selected")
1919
}

api/src/main/java/com/getcode/network/BalanceController.kt

Lines changed: 8 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -51,17 +51,12 @@ data class BalanceDisplay(
5151
open class BalanceController @Inject constructor(
5252
exchange: Exchange,
5353
networkObserver: NetworkConnectivityListener,
54-
getCurrency: suspend (rates: Map<CurrencyCode, Rate>, selected: String?) -> Currency,
55-
@ApplicationContext
56-
private val context: Context,
5754
private val balanceRepository: BalanceRepository,
5855
private val transactionRepository: TransactionRepository,
5956
private val accountRepository: AccountRepository,
6057
private val privacyMigration: PrivacyMigration,
6158
private val transactionReceiver: TransactionReceiver,
62-
prefs: PrefRepository,
63-
getDefaultCurrency: () -> CurrencyCode?,
64-
getCurrencyFromCode: (CurrencyCode?) -> Currency?,
59+
private val getCurrencyFromCode: (CurrencyCode?) -> Currency?,
6560
val suffix: (Currency?) -> String,
6661
) {
6762
private val scope = CoroutineScope(Dispatchers.IO)
@@ -70,16 +65,6 @@ open class BalanceController @Inject constructor(
7065
val rawBalance: Double
7166
get() = balanceRepository.balanceFlow.value
7267

73-
private val preferredCurrency: StateFlow<Currency?> =
74-
prefs.observeOrDefault(
75-
PrefsString.KEY_BALANCE_CURRENCY_SELECTED,
76-
getDefaultCurrency()?.name.orEmpty()
77-
).mapNotNull { CurrencyCode.tryValueOf(it) }
78-
.map { getCurrencyFromCode(it) }
79-
.distinctUntilChanged()
80-
.onEach { Timber.d("currency for balance is now ${it?.code}") }
81-
.stateIn(scope, SharingStarted.Eagerly, getCurrencyFromCode(getDefaultCurrency()))
82-
8368
private val _balanceDisplay = MutableStateFlow<BalanceDisplay?>(null)
8469

8570
val formattedBalance: StateFlow<BalanceDisplay?>
@@ -88,33 +73,19 @@ open class BalanceController @Inject constructor(
8873

8974
init {
9075
combine(
91-
exchange.observeRates()
92-
.distinctUntilChanged()
76+
exchange.observeLocalRate()
9377
.flowOn(Dispatchers.IO)
94-
.flatMapLatest {
95-
combine(
96-
flowOf(it),
97-
preferredCurrency
98-
) { a, b -> a to b }
99-
}
100-
.map { (rates, preferred) ->
101-
getCurrency(rates, preferred?.code)
102-
}
10378
.onEach {
10479
val display = _balanceDisplay.value ?: BalanceDisplay()
105-
_balanceDisplay.value = display.copy(currency = it)
80+
_balanceDisplay.value = display.copy(currency = getCurrencyFromCode(it.currency))
10681
}
107-
.mapNotNull { currency -> CurrencyCode.tryValueOf(currency.code) }
108-
.mapNotNull {
109-
exchange.fetchRatesIfNeeded()
110-
exchange.rateFor(it)
111-
},
82+
.onEach { exchange.fetchRatesIfNeeded() },
11283
balanceRepository.balanceFlow,
11384
networkObserver.state
11485
) { rate, balance, _ ->
11586
rate to balance.coerceAtLeast(0.0)
11687
}.map { (rate, balance) ->
117-
refreshBalance(balance, rate.fx)
88+
refreshBalance(balance, rate)
11889
}.distinctUntilChanged().onEach { (marketValue, amountText) ->
11990
val display = _balanceDisplay.value ?: BalanceDisplay()
12091
_balanceDisplay.value =
@@ -226,9 +197,9 @@ open class BalanceController @Inject constructor(
226197
}
227198
}
228199

229-
private fun refreshBalance(balance: Double, rate: Double): Pair<Double, String> {
230-
val preferredCurrency = preferredCurrency.value
231-
val fiatValue = FormatUtils.getFiatValue(balance, rate)
200+
private fun refreshBalance(balance: Double, rate: Rate): Pair<Double, String> {
201+
val preferredCurrency = getCurrencyFromCode(rate.currency)
202+
val fiatValue = FormatUtils.getFiatValue(balance, rate.fx)
232203

233204
val prefix =
234205
formatPrefix(preferredCurrency).takeIf { it != preferredCurrency?.code }.orEmpty()

api/src/main/java/com/getcode/network/exchange/Exchange.kt

Lines changed: 63 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,28 @@ import android.annotation.SuppressLint
44
import com.getcode.db.Database
55
import com.getcode.model.Currency
66
import com.getcode.model.CurrencyCode
7+
import com.getcode.model.PrefsString
78
import com.getcode.model.Rate
89
import com.getcode.network.api.CurrencyApi
910
import com.getcode.network.core.NetworkOracle
11+
import com.getcode.network.repository.PrefRepository
1012
import com.getcode.utils.ErrorUtils
13+
import com.getcode.utils.TraceType
14+
import com.getcode.utils.trace
1115
import kotlinx.coroutines.CoroutineScope
1216
import kotlinx.coroutines.Dispatchers
1317
import kotlinx.coroutines.flow.Flow
1418
import kotlinx.coroutines.flow.MutableStateFlow
19+
import kotlinx.coroutines.flow.combine
20+
import kotlinx.coroutines.flow.distinctUntilChanged
1521
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
1629
import kotlinx.coroutines.launch
1730
import kotlinx.coroutines.suspendCancellableCoroutine
1831
import timber.log.Timber
@@ -28,6 +41,8 @@ interface Exchange {
2841
val localRate: Rate
2942
fun observeLocalRate(): Flow<Rate>
3043

44+
val entryRate: Rate
45+
3146
fun rates(): Map<CurrencyCode, Rate>
3247
fun observeRates(): Flow<Map<CurrencyCode, Rate>>
3348

@@ -42,6 +57,9 @@ class ExchangeNull : Exchange {
4257
override val localRate: Rate
4358
get() = Rate.oneToOne
4459

60+
override val entryRate: Rate
61+
get() = Rate.oneToOne
62+
4563
override fun observeLocalRate(): Flow<Rate> {
4664
return emptyFlow()
4765
}
@@ -69,12 +87,15 @@ class ExchangeNull : Exchange {
6987
class CodeExchange @Inject constructor(
7088
private val currencyApi: CurrencyApi,
7189
private val networkOracle: NetworkOracle,
72-
private val defaultCurrency: () -> Currency?,
90+
prefs: PrefRepository,
91+
private val defaultCurrency: suspend () -> Currency?,
7392
) : Exchange, CoroutineScope by CoroutineScope(Dispatchers.IO) {
7493

7594
private val db = Database.getInstance()
7695

77-
private var entryRate: Rate = Rate.oneToOne
96+
private var _entryRate: Rate = Rate.oneToOne
97+
override val entryRate: Rate
98+
get() = _entryRate
7899

79100
private val _localRate = MutableStateFlow(Rate.oneToOne)
80101
override val localRate
@@ -116,6 +137,19 @@ class CodeExchange @Inject constructor(
116137

117138
fetchRatesIfNeeded()
118139
}
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)
119153
}
120154

121155
override suspend fun fetchRatesIfNeeded() {
@@ -130,67 +164,71 @@ class CodeExchange @Inject constructor(
130164
}
131165
}
132166

133-
private fun set(currency: CurrencyCode) {
167+
private suspend fun set(currency: CurrencyCode) {
134168
entryCurrency = currency
135169
updateRates()
136170
}
137171

138-
private fun set(ratesBox: RatesBox) {
172+
private suspend fun set(ratesBox: RatesBox) {
139173
rates = ratesBox
140174
rateDate = ratesBox.dateMillis
141175

142176
setLocalEntryCurrencyIfNeeded()
143177
updateRates()
144178
}
145179

146-
private fun setLocalEntryCurrencyIfNeeded() {
147-
if (entryCurrency == null) {
180+
private suspend fun setLocalEntryCurrencyIfNeeded() {
181+
if (entryCurrency != null) {
148182
return
149183
}
150184

151185
val localRegionCurrency = defaultCurrency() ?: return
152-
153-
entryCurrency = CurrencyCode.tryValueOf(localRegionCurrency.code)
186+
val currency = CurrencyCode.tryValueOf(localRegionCurrency.code)
187+
entryCurrency = currency
154188
}
155189

156190
override fun rateFor(currencyCode: CurrencyCode): Rate? = rates.rateFor(currencyCode)
157191

158192
override fun rateForUsd(): Rate? = rates.rateForUsd()
159193

160-
private fun updateRates() {
194+
private suspend fun updateRates() {
161195
if (rates.isEmpty) {
162196
return
163197
}
164198

165-
val localCurrency = defaultCurrency()
199+
val localCurrency = CurrencyCode.tryValueOf(defaultCurrency()?.code.orEmpty())
166200
val rate = localCurrency?.let { rates.rateFor(it) }
167201
_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
174207
)
175208
rate
176209
} 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+
)
178214
rates.rateForUsd()!!
179215
}
180216

181217

182218
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
190225
)
191226
entryRate
192227
} 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+
)
194232
rates.rateForUsd()!!
195233
}
196234

api/src/main/java/com/getcode/solana/organizer/Tray.kt

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import com.getcode.model.RelationshipBox
1111
import com.getcode.solana.keys.PublicKey
1212
import com.getcode.utils.TraceType
1313
import com.getcode.utils.timedTrace
14+
import com.getcode.utils.trace
1415
import kotlin.math.min
1516

1617
class Tray(
@@ -422,18 +423,18 @@ class Tray(
422423
val currentSlot = slots[slots.size - i] // Backwards
423424
val smallerSlot = slotDown(currentSlot.type)
424425

425-
print("$padding o Checking slot: ${currentSlot.type}")
426+
trace("$padding o Checking slot: ${currentSlot.type}", type = TraceType.Silent)
426427

427428
if (smallerSlot == null) {
428429
// We're at the lowest denomination
429430
// so we can't exchange anymore.
430-
print("$padding x Last slot")
431+
trace("$padding x Last slot", type = TraceType.Silent)
431432
break
432433
}
433434

434435
if (currentSlot.billCount() <= 0) {
435436
// Nothing to exchange, the current slot is empty.
436-
print("$padding x Empty")
437+
trace("$padding x Empty", type = TraceType.Silent)
437438
continue
438439
}
439440

@@ -442,7 +443,7 @@ class Tray(
442443
if (smallerSlot.billCount() >= howManyFit - 1) {
443444
// No reason to exchange yet, the smaller slot
444445
// already has enough bills for most payments
445-
print("$padding x Enough bills")
446+
trace("$padding x Enough bills", type = TraceType.Silent)
446447
continue
447448
}
448449

@@ -452,7 +453,10 @@ class Tray(
452453
decrement(AccountType.Bucket(currentSlot.type), kin = amount)
453454
increment(AccountType.Bucket(smallerSlot.type), kin = amount)
454455

455-
print("$padding v Exchanging from ${currentSlot.type} to ${smallerSlot.type} $amount Kin")
456+
trace(
457+
message = "$padding v Exchanging from ${currentSlot.type} to ${smallerSlot.type} $amount Kin",
458+
type = TraceType.Silent
459+
)
456460

457461
exchanges.add(
458462
InternalExchange(
@@ -484,17 +488,17 @@ class Tray(
484488

485489
val exchanges = mutableListOf<InternalExchange>()
486490

487-
for (i in 0 until slots.size) {
491+
for (element in slots) {
488492

489-
val currentSlot = slots[i] // Forwards
493+
val currentSlot = element // Forwards
490494
val largerSlot = slotUp(currentSlot.type)
491495

492-
print("$padding o Checking slot: ${currentSlot.type}")
496+
trace("$padding o Checking slot: ${currentSlot.type}")
493497

494498
if (largerSlot == null) {
495499
// We're at the largest denomination
496500
// so we can't exchange anymore.
497-
print("$padding x Last slot")
501+
trace("$padding x Last slot", type = TraceType.Silent)
498502
break
499503
}
500504

@@ -508,7 +512,7 @@ class Tray(
508512
if (howManyWeHave < ((howManyFit * 2) - 1)) {
509513
// We don't have enough bills to exchange, so we can't do
510514
// anything in this slot at the moment.
511-
print("$padding x Not enough bills")
515+
trace("$padding x Not enough bills", type = TraceType.Silent)
512516
continue
513517
}
514518

@@ -532,7 +536,10 @@ class Tray(
532536
increment(AccountType.Bucket(largerSlot.type), kin = amount)
533537

534538
slotTransfers.forEach { transfer ->
535-
print("$padding v Exchanging from ${transfer.from} to {transfer.to!} {transfer.kin} Kin")
539+
trace(
540+
message = "$padding v Exchanging from ${transfer.from} to {transfer.to!} {transfer.kin} Kin",
541+
type = TraceType.Silent
542+
)
536543
}
537544

538545
exchanges.addAll(

0 commit comments

Comments
 (0)