diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 882f1184..d02c163e 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -35,7 +35,7 @@ android { applicationId = "ltd.grunt.brainwallet" minSdk = 29 targetSdk = 35 - versionCode = 202506327 + versionCode = 202506328 versionName = "v4.9.1" multiDexEnabled = true base.archivesName.set("${defaultConfig.versionName}(${defaultConfig.versionCode})") @@ -200,6 +200,7 @@ dependencies { implementation(project(":iap")) implementation(project(":core")) implementation("androidx.webkit:webkit:1.9.0") + implementation(libs.androidx.benchmark.traceprocessor) testImplementation(testFixtures(project(":app"))) androidTestImplementation(testFixtures(project(":app"))) implementation(grunt.androidx.core.ktx) diff --git a/app/src/main/java/com/brainwallet/ui/bentosections/ltcpickerbento/LTCPickerBentoScreen.kt b/app/src/main/java/com/brainwallet/ui/bentosections/ltcpickerbento/LTCPickerBentoScreen.kt index 1d443c5a..0785abc0 100644 --- a/app/src/main/java/com/brainwallet/ui/bentosections/ltcpickerbento/LTCPickerBentoScreen.kt +++ b/app/src/main/java/com/brainwallet/ui/bentosections/ltcpickerbento/LTCPickerBentoScreen.kt @@ -27,7 +27,6 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.PreviewLightDark import androidx.compose.ui.unit.dp @@ -38,7 +37,6 @@ import com.brainwallet.ui.composable.WheelPickerFocusVertical import com.brainwallet.ui.composable.rememberWheelPickerState import com.brainwallet.ui.theme.IBMPlexSans import com.brainwallet.ui.theme.mainBentoSurface -import kotlinx.coroutines.delay import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter @@ -68,18 +66,15 @@ fun LTCPickerBentoScreen( } val wheelPickerState = rememberWheelPickerState(initialIndex = 0) - var resizedFiatFontSize by remember { mutableStateOf(16.sp) } - var resizedCurrencyNameFontSize by remember { mutableStateOf(18.sp) } - var resizedAsOfTimestampFontSize by remember { mutableStateOf(12.sp) } + var resizedFiatFontSize by remember { mutableStateOf(26.sp) } + var resizedAsOfTimestampFontSize by remember { mutableStateOf(13.sp) } val context = LocalContext.current - // Set the initial index to the selected fiat currency - LaunchedEffect(Unit) { - delay(500) - wheelPickerState.scrollToIndex(state.getSelectedFiatRateIndex()) + val selectedIndex = state.getSelectedFiatRateIndex() + LaunchedEffect(selectedIndex) { + wheelPickerState.scrollToIndex(selectedIndex) } - // Listen for changes in the selected fiat currency index LaunchedEffect(wheelPickerState) { snapshotFlow { wheelPickerState.currentIndex } .filter { it > -1 } @@ -117,7 +112,43 @@ fun LTCPickerBentoScreen( ) .padding(horizontal = 6.dp, vertical = 2.dp) ) - Spacer(modifier = Modifier.weight(0.5f)) + Text( + text = state.formattedFiat, + modifier = Modifier.fillMaxWidth().padding(top = 4.dp), + onTextLayout = { textLayoutResult -> + if (textLayoutResult.hasVisualOverflow) { + resizedFiatFontSize *= 0.95f + } + }, + style = TextStyle( + fontFamily = IBMPlexSans, + fontWeight = FontWeight.Normal, + fontSize = resizedFiatFontSize, + color = if (state.darkMode) Color.White else Color.Black + ), + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + + Text( + text = state.formattedTimeStamp, + modifier = Modifier.fillMaxWidth().padding(top = 4.dp), + onTextLayout = { textLayoutResult -> + if (textLayoutResult.hasVisualOverflow) { + resizedAsOfTimestampFontSize *= 0.95f + } + }, + style = TextStyle( + fontFamily = IBMPlexSans, + fontWeight = FontWeight.Normal, + fontSize = resizedAsOfTimestampFontSize, + color = if (state.darkMode) Color.White else Color.Black + ), + maxLines = 2, + overflow = TextOverflow.Ellipsis + ) + + Spacer(modifier = Modifier.weight(1f)) VerticalWheelPicker( modifier = Modifier .fillMaxWidth() @@ -151,65 +182,6 @@ fun LTCPickerBentoScreen( ) ) } - Text( - text = "${state.selectedCurrency.name}", - modifier = Modifier - .fillMaxWidth() - .padding(vertical = 8.dp), - onTextLayout = { textLayoutResult -> - if (textLayoutResult.hasVisualOverflow) { - resizedCurrencyNameFontSize *= 0.95f - } - }, - style = TextStyle( - fontFamily = IBMPlexSans, - fontWeight = FontWeight.Light, - fontSize = resizedCurrencyNameFontSize, - color = if (state.darkMode) Color.White else Color.Black - ), - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - Text( - text = state.formattedFiat, - modifier = Modifier.fillMaxWidth().padding(bottom = 4.dp), - onTextLayout = { textLayoutResult -> - if (textLayoutResult.hasVisualOverflow) { - resizedFiatFontSize *= 0.95f - } - }, - style = TextStyle( - fontFamily = IBMPlexSans, - fontWeight = FontWeight.Normal, - fontSize = resizedFiatFontSize, - color = if (state.darkMode) Color.White else Color.Black - ), - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - Text( - text = stringResource( - com.brainwallet.R.string.ltc_ticker_as_of_timestamp, - state.formattedTimeStamp - ), - modifier = Modifier - .fillMaxWidth() - .padding(top = 2.dp, bottom = 4.dp), - onTextLayout = { textLayoutResult -> - if (textLayoutResult.hasVisualOverflow) { - resizedAsOfTimestampFontSize *= 0.95f - } - }, - style = TextStyle( - fontFamily = IBMPlexSans, - fontWeight = FontWeight.Normal, - fontSize = resizedAsOfTimestampFontSize, - color = if (state.darkMode) Color.White else Color.Black, - textAlign = TextAlign.Start - ), - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) } } } diff --git a/app/src/main/java/com/brainwallet/ui/bentosections/ltcpickerbento/LTCPickerBentoViewModel.kt b/app/src/main/java/com/brainwallet/ui/bentosections/ltcpickerbento/LTCPickerBentoViewModel.kt index 0254e925..1517c3e2 100644 --- a/app/src/main/java/com/brainwallet/ui/bentosections/ltcpickerbento/LTCPickerBentoViewModel.kt +++ b/app/src/main/java/com/brainwallet/ui/bentosections/ltcpickerbento/LTCPickerBentoViewModel.kt @@ -1,10 +1,12 @@ package com.brainwallet.ui.bentosections.ltcpickerbento import androidx.lifecycle.viewModelScope +import com.brainwallet.constants.BWConstants import com.brainwallet.data.repository.LtcRepository import com.brainwallet.data.repository.SettingRepository import com.brainwallet.tools.sqlite.CurrencyDataSource import com.brainwallet.ui.BrainwalletViewModel +import com.brainwallet.util.CurrencyDataGetter import com.google.firebase.crashlytics.FirebaseCrashlytics import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow @@ -14,18 +16,20 @@ import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import org.koin.android.annotation.KoinViewModel import timber.log.Timber +import java.math.BigDecimal @KoinViewModel class LTCPickerBentoViewModel( private val settingRepository: SettingRepository, private val currencyDataSource: CurrencyDataSource, + private val currencyDataGetter: CurrencyDataGetter, private val ltcRepository: LtcRepository ) : BrainwalletViewModel() { private val _state = MutableStateFlow(LTCPickerBentoState()) val state: StateFlow = _state.asStateFlow() val formatter = java.text.SimpleDateFormat( - "MMM dd, yyyy h:mm:ss a", + "MMM dd, h:mm:ss a", java.util.Locale.getDefault() ) @@ -66,16 +70,26 @@ class LTCPickerBentoViewModel( ) { val rates = ltcRepository.fetchRates() val selectedFiat = rates.find { it.code == currencyCode } - var formattedFiat = "" - val msg = "||fetchRates ${selectedFiat?.rate} fetch ltc stats: $state.ltcStats.currentBlockHeight" - Timber.d("timber: ltcStats: $state.ltcStats.value") - Timber.d(msg) - FirebaseCrashlytics.getInstance().log(msg) + val iso = currencyDataGetter.getIsoSymbol() + var formattedCurrency: String? = null + val currency = currencyDataGetter.getCurrencyByIso(iso) + if (currency != null) { + val roundedPriceAmount: BigDecimal = + BigDecimal(currency.rate.toDouble()).multiply(BigDecimal(100)) + .divide(BigDecimal(100), 2, BWConstants.ROUNDING_MODE) + formattedCurrency = + currencyDataGetter.getFormattedCurrencyString( + iso, + roundedPriceAmount + ) + } else { + Timber.w("The currency related to %s is NULL", iso) + } _state.update { it.copy( selectedCurrency = selectedFiat ?: return@update it, - formattedFiat = "${selectedFiat.symbol} ${"%6.2f".format(selectedFiat.rate)}", + formattedFiat = formattedCurrency ?: "", formattedTimeStamp = formatter.format(java.util.Date()), ltcStats = ltcRepository.ltcStats.value ) diff --git a/app/src/test/kotlin/com/brainwallet/ui/bentosections/ltcpickerbento/LTCPickerBentoViewModelTests.kt b/app/src/test/kotlin/com/brainwallet/ui/bentosections/ltcpickerbento/LTCPickerBentoViewModelTests.kt index 3d770bf3..fd98fb6b 100644 --- a/app/src/test/kotlin/com/brainwallet/ui/bentosections/ltcpickerbento/LTCPickerBentoViewModelTests.kt +++ b/app/src/test/kotlin/com/brainwallet/ui/bentosections/ltcpickerbento/LTCPickerBentoViewModelTests.kt @@ -5,6 +5,7 @@ import com.brainwallet.data.model.GlobalCurrency import com.brainwallet.data.repository.LtcRepository import com.brainwallet.data.repository.SettingRepository import com.brainwallet.tools.sqlite.CurrencyDataSource +import com.brainwallet.util.CurrencyDataGetter import io.mockk.coEvery import io.mockk.every import io.mockk.mockk @@ -38,6 +39,7 @@ class LTCPickerBentoViewModelTest { every { settings } returns settingsFlow } private val currencyDataSource: CurrencyDataSource = mockk() + private val currencyDataGetter: CurrencyDataGetter = mockk() private lateinit var viewModel: LTCPickerBentoViewModel private val mockCrashlytics: FirebaseCrashlytics = mockk(relaxed = true) @@ -52,6 +54,7 @@ class LTCPickerBentoViewModelTest { viewModel = LTCPickerBentoViewModel( settingRepository, currencyDataSource, + currencyDataGetter, ltcRepository ) } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index dd78680f..f74782b1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -33,6 +33,7 @@ runtime = "1.10.6" foundation = "1.10.6" animation = "1.10.6" play-services-games = "24.0.0" +benchmark-traceprocessor = "1.4.1" [libraries] androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "androidx-appcompat" } @@ -107,6 +108,7 @@ androidx-runtime = { group = "androidx.compose.runtime", name = "runtime", versi androidx-foundation = { group = "androidx.compose.foundation", name = "foundation", version.ref = "foundation" } androidx-animation = { group = "androidx.compose.animation", name = "animation", version.ref = "animation" } play-services-games = { group = "com.google.android.gms", name = "play-services-games", version.ref = "play-services-games" } +androidx-benchmark-traceprocessor = { group = "androidx.benchmark", name = "benchmark-traceprocessor", version.ref = "benchmark-traceprocessor" } [bundles] androidx-lifecycle = ["androidx-lifecycle-runtime", "androidx-lifecycle-viewmodel", "androidx-lifecycle-viewmodel-compose"]