Skip to content

Commit 45852b3

Browse files
committed
fix: avoid duplicate rate writes
1 parent d8217db commit 45852b3

2 files changed

Lines changed: 33 additions & 5 deletions

File tree

app/src/main/java/to/bitkit/ui/screens/widgets/calculator/CalculatorViewModel.kt

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ class CalculatorViewModel @Inject constructor(
4646
val uiState: StateFlow<CalculatorUiState> = _uiState.asStateFlow()
4747
private var pendingValues: CalculatorValues? = null
4848
private var lastCurrencyKey: CalculatorCurrencyKey? = null
49+
private var lastRates: ImmutableList<FxRate>? = null
4950
private var activeInput: MoneyType? = null
5051

5152
val isCalculatorWidgetEnabled: StateFlow<Boolean> = widgetsRepo.widgetsDataFlow
@@ -164,14 +165,17 @@ class CalculatorViewModel @Inject constructor(
164165
val currencyKey = CalculatorCurrencyKey(
165166
selectedCurrency = currencyState.selectedCurrency,
166167
displayUnit = currencyState.displayUnit,
167-
rates = currencyState.rates,
168168
)
169169
val previousCurrencyKey = lastCurrencyKey
170+
val previousRates = lastRates
170171
lastCurrencyKey = currencyKey
172+
lastRates = currencyState.rates
171173

172-
val currencyChanged = previousCurrencyKey != null && previousCurrencyKey != currencyKey
174+
val currencyChanged = previousCurrencyKey != null &&
175+
previousCurrencyKey.selectedCurrency != currencyKey.selectedCurrency
173176
val displayUnitChanged = previousCurrencyKey != null &&
174177
previousCurrencyKey.displayUnit != currencyKey.displayUnit
178+
val ratesChanged = previousRates != null && previousRates != currencyState.rates
175179
val isInitialSync = previousCurrencyKey == null
176180
val nextActiveValues = deriveActiveValues(
177181
activeValues = activeValues,
@@ -188,7 +192,7 @@ class CalculatorViewModel @Inject constructor(
188192
)
189193
}
190194

191-
val shouldRefreshFiat = isInitialSync || currencyChanged || shouldHydrateFiatFromStoredBtc(
195+
val shouldRefreshFiat = isInitialSync || currencyChanged || ratesChanged || shouldHydrateFiatFromStoredBtc(
192196
storedBtcValue = storedValues.btcValue,
193197
storedFiatValue = storedValues.fiatValue,
194198
currentFiatValue = nextActiveValues.fiatValue,
@@ -219,7 +223,10 @@ class CalculatorViewModel @Inject constructor(
219223
if (convertedFiat.isEmpty()) return persistCanonicalValues(activeValues, nextActiveValues)
220224

221225
val updatedValues = nextActiveValues.copy(fiatValue = convertedFiat)
222-
updateCalculatorValues(updatedValues)
226+
persistCanonicalValuesIfNeeded(
227+
activeValues = activeValues,
228+
nextActiveValues = updatedValues,
229+
)
223230
return updatedValues
224231
}
225232

@@ -371,7 +378,6 @@ data class CalculatorUiState(
371378
private data class CalculatorCurrencyKey(
372379
val selectedCurrency: String,
373380
val displayUnit: BitcoinDisplayUnit,
374-
val rates: ImmutableList<FxRate>,
375381
)
376382

377383
internal fun shouldHydrateFiatFromStoredBtc(

app/src/test/java/to/bitkit/ui/screens/widgets/calculator/CalculatorViewModelTest.kt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class CalculatorViewModelTest : BaseUnitTest() {
3535
private var fiatConversionValue: String? = null
3636
private var fiatConversionFormatted: String? = null
3737
private var fiatToSatsValue = 12_345uL
38+
private var updateCalculatorValuesCalls = 0
3839

3940
private lateinit var sut: CalculatorViewModel
4041

@@ -47,6 +48,7 @@ class CalculatorViewModelTest : BaseUnitTest() {
4748
fiatConversionValue = null
4849
fiatConversionFormatted = null
4950
fiatToSatsValue = 12_345uL
51+
updateCalculatorValuesCalls = 0
5052

5153
whenever(widgetsRepo.widgetsDataFlow).thenReturn(widgetsData)
5254
whenever(currencyRepo.currencyState).thenReturn(currencyState)
@@ -65,6 +67,7 @@ class CalculatorViewModelTest : BaseUnitTest() {
6567
}
6668
whenever(currencyRepo.convertFiatToSats(any<BigDecimal>(), anyOrNull())).thenAnswer { fiatToSatsValue }
6769
whenever { widgetsRepo.updateCalculatorValues(any()) }.thenAnswer {
70+
updateCalculatorValuesCalls++
6871
val calculatorValues = it.getArgument<CalculatorValues>(0)
6972
widgetsData.value = widgetsData.value.copy(calculatorValues = calculatorValues)
7073
Unit
@@ -290,6 +293,25 @@ class CalculatorViewModelTest : BaseUnitTest() {
290293
assertEquals("7.50", widgetsData.value.calculatorValues.fiatValue)
291294
}
292295

296+
@Test
297+
fun `rate refresh skips persist when fiat display value is unchanged`() = test {
298+
sut = createSut()
299+
advanceUntilIdle()
300+
301+
sut.onBtcInputChanged("10000")
302+
advanceUntilIdle()
303+
304+
val updatesBeforeRateRefresh = updateCalculatorValuesCalls
305+
currencyState.value = currencyState.value.copy(
306+
rates = persistentListOf(fxRate(lastPrice = "62501")),
307+
)
308+
advanceUntilIdle()
309+
310+
assertEquals("10000", sut.uiState.value.btcValue)
311+
assertEquals("6.25", sut.uiState.value.fiatValue)
312+
assertEquals(updatesBeforeRateRefresh, updateCalculatorValuesCalls)
313+
}
314+
293315
@Test
294316
fun `currency change preserves fiat input as source`() = test {
295317
sut = createSut()

0 commit comments

Comments
 (0)