From 86b50bab43d9b75e1036134f96603b4200320150 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Mon, 18 May 2026 21:01:27 +0200 Subject: [PATCH] fix: polish widget foundation --- .../headlines/HeadlinesPreviewContentTest.kt | 4 +- .../config/AppWidgetConfigActivity.kt | 9 ++- .../appwidget/config/BlocksConfigContent.kt | 6 +- .../config/HeadlinesConfigContent.kt | 6 +- .../appwidget/config/PriceConfigContent.kt | 6 +- .../appwidget/config/WeatherConfigContent.kt | 7 +-- .../appwidget/ui/facts/FactsGlanceContent.kt | 8 ++- .../to/bitkit/data/widgets/PriceService.kt | 46 +++++++++------ .../widgets/blocks/BlocksEditScreen.kt | 9 ++- .../widgets/blocks/BlocksPreviewScreen.kt | 9 ++- .../widgets/components/WidgetSizeCarousel.kt | 58 +++++++++++-------- .../widgets/facts/FactsPreviewScreen.kt | 9 ++- .../widgets/headlines/HeadlinesEditScreen.kt | 9 ++- .../headlines/HeadlinesPreviewScreen.kt | 9 ++- .../screens/widgets/price/PriceEditScreen.kt | 8 +-- .../widgets/price/PricePreviewScreen.kt | 9 ++- .../widgets/weather/WeatherEditScreen.kt | 6 +- .../widgets/weather/WeatherPreviewScreen.kt | 6 +- .../main/res/xml/appwidget_info_blocks.xml | 1 + .../main/res/xml/appwidget_info_headlines.xml | 1 + app/src/main/res/xml/appwidget_info_price.xml | 1 + .../main/res/xml/appwidget_info_weather.xml | 1 + .../bitkit/data/widgets/PriceServiceTest.kt | 31 ++++++++++ changelog.d/next/936.fixed.md | 1 + 24 files changed, 147 insertions(+), 113 deletions(-) create mode 100644 app/src/test/java/to/bitkit/data/widgets/PriceServiceTest.kt create mode 100644 changelog.d/next/936.fixed.md diff --git a/app/src/androidTest/java/to/bitkit/ui/screens/widgets/headlines/HeadlinesPreviewContentTest.kt b/app/src/androidTest/java/to/bitkit/ui/screens/widgets/headlines/HeadlinesPreviewContentTest.kt index e7b6ec8e1..12e146a3b 100644 --- a/app/src/androidTest/java/to/bitkit/ui/screens/widgets/headlines/HeadlinesPreviewContentTest.kt +++ b/app/src/androidTest/java/to/bitkit/ui/screens/widgets/headlines/HeadlinesPreviewContentTest.kt @@ -56,7 +56,7 @@ class HeadlinesPreviewContentTest { // Verify settings and preview section composeTestRule.onNodeWithTag("WidgetEdit").assertExists() composeTestRule.onNodeWithTag("headlines_preview_carousel").assertExists() - composeTestRule.onNodeWithTag("headline_card_small").assertExists() + composeTestRule.onNodeWithTag("headline_card_wide").assertExists() // Verify buttons composeTestRule.onNodeWithTag("buttons_row").assertExists() @@ -162,7 +162,7 @@ class HeadlinesPreviewContentTest { composeTestRule.onNodeWithTag("divider").assertExists() composeTestRule.onNodeWithTag("WidgetEdit").assertExists() composeTestRule.onNodeWithTag("headlines_preview_carousel").assertExists() - composeTestRule.onNodeWithTag("headline_card_small").assertExists() + composeTestRule.onNodeWithTag("headline_card_wide").assertExists() composeTestRule.onNodeWithTag("buttons_row").assertExists() composeTestRule.onNodeWithTag("WidgetDelete").assertExists() composeTestRule.onNodeWithTag("WidgetSave").assertExists() diff --git a/app/src/main/java/to/bitkit/appwidget/config/AppWidgetConfigActivity.kt b/app/src/main/java/to/bitkit/appwidget/config/AppWidgetConfigActivity.kt index 976a32c9e..2866db9fb 100644 --- a/app/src/main/java/to/bitkit/appwidget/config/AppWidgetConfigActivity.kt +++ b/app/src/main/java/to/bitkit/appwidget/config/AppWidgetConfigActivity.kt @@ -1,6 +1,5 @@ package to.bitkit.appwidget.config -import android.app.Activity import android.appwidget.AppWidgetManager import android.content.Intent import android.os.Bundle @@ -20,6 +19,7 @@ import to.bitkit.appwidget.ui.price.PriceGlanceWidget import to.bitkit.appwidget.ui.weather.WeatherGlanceReceiver import to.bitkit.appwidget.ui.weather.WeatherGlanceWidget import to.bitkit.ui.theme.AppThemeSurface +import to.bitkit.ui.utils.enableAppEdgeToEdge import to.bitkit.utils.Logger @AndroidEntryPoint @@ -34,6 +34,7 @@ class AppWidgetConfigActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + enableAppEdgeToEdge() val appWidgetId = intent?.extras?.getInt( AppWidgetManager.EXTRA_APPWIDGET_ID, @@ -58,7 +59,9 @@ class AppWidgetConfigActivity : ComponentActivity() { onConfirm = { when (viewModel.uiState.value.type) { AppWidgetType.PRICE -> PriceGlanceWidget().updateAll(this@AppWidgetConfigActivity) - AppWidgetType.HEADLINES -> HeadlinesGlanceWidget().updateAll(this@AppWidgetConfigActivity) + AppWidgetType.HEADLINES -> HeadlinesGlanceWidget().updateAll( + this@AppWidgetConfigActivity, + ) AppWidgetType.BLOCKS -> BlocksGlanceWidget().updateAll(this@AppWidgetConfigActivity) AppWidgetType.FACTS -> Unit AppWidgetType.WEATHER -> WeatherGlanceWidget().updateAll(this@AppWidgetConfigActivity) @@ -68,7 +71,7 @@ class AppWidgetConfigActivity : ComponentActivity() { AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId, ) - setResult(Activity.RESULT_OK, result) + setResult(RESULT_OK, result) finish() }, onCancel = { finish() }, diff --git a/app/src/main/java/to/bitkit/appwidget/config/BlocksConfigContent.kt b/app/src/main/java/to/bitkit/appwidget/config/BlocksConfigContent.kt index 97b687f31..0467326e1 100644 --- a/app/src/main/java/to/bitkit/appwidget/config/BlocksConfigContent.kt +++ b/app/src/main/java/to/bitkit/appwidget/config/BlocksConfigContent.kt @@ -1,7 +1,6 @@ package to.bitkit.appwidget.config import androidx.annotation.DrawableRes -import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -61,10 +60,7 @@ internal fun BlocksConfigContent( ) } - ScreenColumn( - noBackground = true, - modifier = Modifier.background(Colors.Gray7) - ) { + ScreenColumn { AppTopBar( titleText = stringResource(R.string.widgets__blocks__name), onBackClick = onCancel, diff --git a/app/src/main/java/to/bitkit/appwidget/config/HeadlinesConfigContent.kt b/app/src/main/java/to/bitkit/appwidget/config/HeadlinesConfigContent.kt index 9d389993e..1dc4d38a3 100644 --- a/app/src/main/java/to/bitkit/appwidget/config/HeadlinesConfigContent.kt +++ b/app/src/main/java/to/bitkit/appwidget/config/HeadlinesConfigContent.kt @@ -1,6 +1,5 @@ package to.bitkit.appwidget.config -import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -43,10 +42,7 @@ internal fun HeadlinesConfigContent( val prefs = state.headlinePreferences val previewArticle = state.previewArticle - ScreenColumn( - noBackground = true, - modifier = Modifier.background(Colors.Gray7) - ) { + ScreenColumn { AppTopBar( titleText = stringResource(R.string.widgets__news__name), onBackClick = onCancel, diff --git a/app/src/main/java/to/bitkit/appwidget/config/PriceConfigContent.kt b/app/src/main/java/to/bitkit/appwidget/config/PriceConfigContent.kt index 9d4cd3037..6d3f230a6 100644 --- a/app/src/main/java/to/bitkit/appwidget/config/PriceConfigContent.kt +++ b/app/src/main/java/to/bitkit/appwidget/config/PriceConfigContent.kt @@ -1,6 +1,5 @@ package to.bitkit.appwidget.config -import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -44,10 +43,7 @@ internal fun PriceConfigContent( val prefs = state.pricePreferences val selectedPair = prefs.enabledPairs.firstOrNull() ?: TradingPair.BTC_USD - ScreenColumn( - noBackground = true, - modifier = Modifier.background(Colors.Gray7) - ) { + ScreenColumn { AppTopBar( titleText = stringResource(R.string.widgets__price__name), onBackClick = onCancel, diff --git a/app/src/main/java/to/bitkit/appwidget/config/WeatherConfigContent.kt b/app/src/main/java/to/bitkit/appwidget/config/WeatherConfigContent.kt index bb74d87e3..2927cea41 100644 --- a/app/src/main/java/to/bitkit/appwidget/config/WeatherConfigContent.kt +++ b/app/src/main/java/to/bitkit/appwidget/config/WeatherConfigContent.kt @@ -1,6 +1,5 @@ package to.bitkit.appwidget.config -import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -37,15 +36,11 @@ internal fun WeatherConfigContent( onReset: () -> Unit, onSave: () -> Unit, onCancel: () -> Unit, - modifier: Modifier = Modifier, ) { val prefs = state.weatherPreferences val weather = state.previewWeather - ScreenColumn( - noBackground = true, - modifier = modifier.background(Colors.Gray7) - ) { + ScreenColumn { AppTopBar( titleText = stringResource(R.string.widgets__weather__name), onBackClick = onCancel, diff --git a/app/src/main/java/to/bitkit/appwidget/ui/facts/FactsGlanceContent.kt b/app/src/main/java/to/bitkit/appwidget/ui/facts/FactsGlanceContent.kt index a580cef54..52367125f 100644 --- a/app/src/main/java/to/bitkit/appwidget/ui/facts/FactsGlanceContent.kt +++ b/app/src/main/java/to/bitkit/appwidget/ui/facts/FactsGlanceContent.kt @@ -1,5 +1,6 @@ package to.bitkit.appwidget.ui.facts +import android.content.Intent import androidx.compose.runtime.Composable import androidx.compose.ui.unit.dp import androidx.glance.GlanceModifier @@ -7,6 +8,7 @@ import androidx.glance.Image import androidx.glance.ImageProvider import androidx.glance.LocalContext import androidx.glance.LocalSize +import androidx.glance.appwidget.action.actionStartActivity import androidx.glance.layout.Alignment import androidx.glance.layout.Box import androidx.glance.layout.fillMaxSize @@ -18,6 +20,7 @@ import to.bitkit.appwidget.ui.components.CaptionB import to.bitkit.appwidget.ui.components.GlanceLayoutDimens import to.bitkit.appwidget.ui.components.GlanceWidgetScaffold import to.bitkit.appwidget.ui.theme.GlanceTextStyles +import to.bitkit.ui.MainActivity private val BADGE_SIZE = 32.dp private val BADGE_RESERVED_END = 40.dp @@ -28,8 +31,11 @@ fun FactsGlanceContent( fact: String?, ) { val context = LocalContext.current + val openAppIntent = Intent(context, MainActivity::class.java).apply { + addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP) + } - GlanceWidgetScaffold { + GlanceWidgetScaffold(onClick = actionStartActivity(openAppIntent)) { if (fact == null) { CaptionB(text = context.getString(R.string.appwidget__loading)) return@GlanceWidgetScaffold diff --git a/app/src/main/java/to/bitkit/data/widgets/PriceService.kt b/app/src/main/java/to/bitkit/data/widgets/PriceService.kt index 5da7a4938..5c5d9d782 100644 --- a/app/src/main/java/to/bitkit/data/widgets/PriceService.kt +++ b/app/src/main/java/to/bitkit/data/widgets/PriceService.kt @@ -22,7 +22,6 @@ import to.bitkit.models.WidgetType import to.bitkit.utils.AppError import to.bitkit.utils.Logger import java.text.NumberFormat -import java.util.Currency import java.util.Locale import javax.inject.Inject import javax.inject.Singleton @@ -147,24 +146,15 @@ class PriceService @Inject constructor( ) } - private fun formatPrice(pair: TradingPair, price: Double): String { + private fun formatPrice( + pair: TradingPair, + price: Double, + locale: Locale = Locale.getDefault(), + ): String { return runCatching { - val currency = Currency.getInstance(pair.quote) - val numberFormat = NumberFormat.getCurrencyInstance(Locale.US).apply { - this.currency = currency - maximumFractionDigits = when { - price >= 1000 -> 0 - price >= 1 -> 2 - else -> 6 - } - } - - // Format and remove currency symbol, keeping only the number with formatting - val formatted = numberFormat.format(price) - val currencySymbol = currency.symbol - formatted.replace(currencySymbol, "").trim() + formatPriceValue(price = price, locale = locale) }.onFailure { - Logger.warn("Error formatting price for ${pair.displayName}", e = it, context = TAG) + Logger.warn("Failed to format price for '${pair.displayName}'", it, context = TAG) }.getOrDefault(String.format(Locale.US, "%.2f", price)) } @@ -180,3 +170,25 @@ sealed class PriceError(message: String) : AppError(message) { class InvalidResponse(override val message: String) : PriceError(message) class NetworkError(override val message: String) : PriceError(message) } + +private const val GROUPED_PRICE_THRESHOLD = 1_000.0 +private const val STANDARD_PRICE_THRESHOLD = 1.0 +private const val GROUPED_PRICE_DECIMALS = 0 +private const val STANDARD_PRICE_DECIMALS = 2 +private const val SMALL_PRICE_DECIMALS = 6 +private const val MIN_PRICE_DECIMALS = 0 + +internal fun formatPriceValue( + price: Double, + locale: Locale = Locale.getDefault(), +): String { + return NumberFormat.getNumberInstance(locale).apply { + maximumFractionDigits = when { + price >= GROUPED_PRICE_THRESHOLD -> GROUPED_PRICE_DECIMALS + price >= STANDARD_PRICE_THRESHOLD -> STANDARD_PRICE_DECIMALS + else -> SMALL_PRICE_DECIMALS + } + minimumFractionDigits = MIN_PRICE_DECIMALS + isGroupingUsed = true + }.format(price) +} diff --git a/app/src/main/java/to/bitkit/ui/screens/widgets/blocks/BlocksEditScreen.kt b/app/src/main/java/to/bitkit/ui/screens/widgets/blocks/BlocksEditScreen.kt index c7ffc0af4..f852a0f4a 100644 --- a/app/src/main/java/to/bitkit/ui/screens/widgets/blocks/BlocksEditScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/widgets/blocks/BlocksEditScreen.kt @@ -1,7 +1,6 @@ package to.bitkit.ui.screens.widgets.blocks import androidx.annotation.DrawableRes -import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -40,6 +39,7 @@ fun BlocksEditScreen( blocksViewModel: BlocksViewModel, onBack: () -> Unit, navigatePreview: () -> Unit, + modifier: Modifier = Modifier, ) { val customPreference by blocksViewModel.customPreferences.collectAsStateWithLifecycle() val currentBlock by blocksViewModel.currentBlock.collectAsStateWithLifecycle() @@ -67,6 +67,7 @@ fun BlocksEditScreen( onClickShowSource = { blocksViewModel.toggleShowSource() }, onClickReset = { blocksViewModel.resetCustomPreferences() }, onClickPreview = navigatePreview, + modifier = modifier ) } @@ -84,12 +85,10 @@ private fun Content( onClickPreview: () -> Unit, blocksPreferences: BlocksPreferences, block: BlockModel, + modifier: Modifier = Modifier, ) { ScreenColumn( - noBackground = true, - modifier = Modifier - .background(Colors.Gray7) - .testTag("blocks_edit_screen") + modifier = modifier.testTag("blocks_edit_screen") ) { AppTopBar( titleText = stringResource(R.string.widgets__blocks__name), diff --git a/app/src/main/java/to/bitkit/ui/screens/widgets/blocks/BlocksPreviewScreen.kt b/app/src/main/java/to/bitkit/ui/screens/widgets/blocks/BlocksPreviewScreen.kt index 8f6a30b39..bf451492d 100644 --- a/app/src/main/java/to/bitkit/ui/screens/widgets/blocks/BlocksPreviewScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/widgets/blocks/BlocksPreviewScreen.kt @@ -1,6 +1,5 @@ package to.bitkit.ui.screens.widgets.blocks -import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -37,6 +36,7 @@ fun BlocksPreviewScreen( onClose: () -> Unit, onBack: () -> Unit, navigateEditWidget: () -> Unit, + modifier: Modifier = Modifier, ) { val customBlocksPreferences by blocksViewModel.customPreferences.collectAsStateWithLifecycle() val currentBlock by blocksViewModel.currentBlock.collectAsStateWithLifecycle() @@ -60,6 +60,7 @@ fun BlocksPreviewScreen( blocksViewModel.savePreferences() onClose() }, + modifier = modifier ) } @@ -72,12 +73,10 @@ private fun Content( isBlocksWidgetEnabled: Boolean, blocksPreferences: BlocksPreferences, block: BlockModel?, + modifier: Modifier = Modifier, ) { ScreenColumn( - noBackground = true, - modifier = Modifier - .background(Colors.Gray7) - .testTag("blocks_preview_screen") + modifier = modifier.testTag("blocks_preview_screen") ) { AppTopBar( titleText = stringResource(R.string.widgets__blocks__name), diff --git a/app/src/main/java/to/bitkit/ui/screens/widgets/components/WidgetSizeCarousel.kt b/app/src/main/java/to/bitkit/ui/screens/widgets/components/WidgetSizeCarousel.kt index d2492af4f..da173e3c1 100644 --- a/app/src/main/java/to/bitkit/ui/screens/widgets/components/WidgetSizeCarousel.kt +++ b/app/src/main/java/to/bitkit/ui/screens/widgets/components/WidgetSizeCarousel.kt @@ -23,17 +23,23 @@ import to.bitkit.ui.components.Caption13Up import to.bitkit.ui.components.VerticalSpacer import to.bitkit.ui.theme.Colors -private const val PAGE_SMALL = 0 -private const val PAGE_WIDE = 1 -private const val PAGE_COUNT = 2 +private const val PAGE_WIDE = 0 +private const val PAGE_SMALL = 1 + +// temporarily removed until small size widgets variants are implemented +private const val PAGE_COUNT = 1 +// private const val PAGE_COUNT = 2 @Composable +@Suppress("UnusedParameter") fun WidgetSizeCarousel( smallContent: @Composable () -> Unit, wideContent: @Composable () -> Unit, modifier: Modifier = Modifier, ) { - val pagerState = rememberPagerState(pageCount = { PAGE_COUNT }) + val pagerState = rememberPagerState( + pageCount = { PAGE_COUNT }, + ) Column( verticalArrangement = Arrangement.Center, @@ -51,8 +57,9 @@ fun WidgetSizeCarousel( modifier = Modifier.fillMaxWidth() ) { when (page) { - PAGE_SMALL -> smallContent() PAGE_WIDE -> wideContent() + // temporarily removed until small size widgets variants are implemented + // PAGE_SMALL -> smallContent() } } } @@ -61,10 +68,9 @@ fun WidgetSizeCarousel( Caption13Up( text = stringResource( - if (pagerState.currentPage == PAGE_SMALL) { - R.string.widgets__widget__size_small - } else { - R.string.widgets__widget__size_wide + when (pagerState.currentPage) { + PAGE_SMALL -> R.string.widgets__widget__size_small + else -> R.string.widgets__widget__size_wide }, ), color = Colors.White64, @@ -76,22 +82,24 @@ fun WidgetSizeCarousel( VerticalSpacer(16.dp) - Row( - horizontalArrangement = Arrangement.Center, - modifier = Modifier - .fillMaxWidth() - .testTag("page_indicator") - ) { - repeat(PAGE_COUNT) { index -> - Box( - modifier = Modifier - .padding(horizontal = 4.dp) - .size(8.dp) - .background( - color = if (pagerState.currentPage == index) Colors.White else Colors.White32, - shape = CircleShape, - ) - ) + if (PAGE_COUNT > 1) { + Row( + horizontalArrangement = Arrangement.Center, + modifier = Modifier + .fillMaxWidth() + .testTag("page_indicator") + ) { + repeat(PAGE_COUNT) { index -> + Box( + modifier = Modifier + .padding(horizontal = 4.dp) + .size(8.dp) + .background( + color = if (pagerState.currentPage == index) Colors.White else Colors.White32, + shape = CircleShape, + ) + ) + } } } } diff --git a/app/src/main/java/to/bitkit/ui/screens/widgets/facts/FactsPreviewScreen.kt b/app/src/main/java/to/bitkit/ui/screens/widgets/facts/FactsPreviewScreen.kt index 8405a105c..ced880e8a 100644 --- a/app/src/main/java/to/bitkit/ui/screens/widgets/facts/FactsPreviewScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/widgets/facts/FactsPreviewScreen.kt @@ -1,6 +1,5 @@ package to.bitkit.ui.screens.widgets.facts -import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -32,6 +31,7 @@ fun FactsPreviewScreen( factsViewModel: FactsViewModel, onClose: () -> Unit, onBack: () -> Unit, + modifier: Modifier = Modifier, ) { val fact by factsViewModel.currentFact.collectAsStateWithLifecycle() val isFactsWidgetEnabled by factsViewModel.isFactsWidgetEnabled.collectAsStateWithLifecycle() @@ -52,6 +52,7 @@ fun FactsPreviewScreen( factsViewModel.saveWidget() onClose() }, + modifier = modifier ) } @@ -62,12 +63,10 @@ fun FactsPreviewContent( onClickSave: () -> Unit, isFactsWidgetEnabled: Boolean, fact: String, + modifier: Modifier = Modifier, ) { ScreenColumn( - noBackground = true, - modifier = Modifier - .background(Colors.Gray7) - .testTag("facts_preview_screen") + modifier = modifier.testTag("facts_preview_screen") ) { AppTopBar( titleText = stringResource(R.string.widgets__facts__name), diff --git a/app/src/main/java/to/bitkit/ui/screens/widgets/headlines/HeadlinesEditScreen.kt b/app/src/main/java/to/bitkit/ui/screens/widgets/headlines/HeadlinesEditScreen.kt index f8faed4e6..6d47f628c 100644 --- a/app/src/main/java/to/bitkit/ui/screens/widgets/headlines/HeadlinesEditScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/widgets/headlines/HeadlinesEditScreen.kt @@ -1,6 +1,5 @@ package to.bitkit.ui.screens.widgets.headlines -import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -40,6 +39,7 @@ fun HeadlinesEditScreen( headlinesViewModel: HeadlinesViewModel, onBack: () -> Unit, navigatePreview: () -> Unit, + modifier: Modifier = Modifier, ) { val customHeadlinePreferences by headlinesViewModel.customPreferences.collectAsStateWithLifecycle() val article by headlinesViewModel.currentArticle.collectAsStateWithLifecycle() @@ -60,6 +60,7 @@ fun HeadlinesEditScreen( onClickPreview = { navigatePreview() }, + modifier = modifier ) } @@ -72,12 +73,10 @@ fun HeadlinesEditContent( onClickShowSource: () -> Unit, headlinePreferences: HeadlinePreferences, article: ArticleModel, + modifier: Modifier = Modifier, ) { ScreenColumn( - noBackground = true, - modifier = Modifier - .background(Colors.Gray7) - .testTag("headlines_edit_screen") + modifier = modifier.testTag("headlines_edit_screen") ) { AppTopBar( titleText = stringResource(R.string.widgets__news__name), diff --git a/app/src/main/java/to/bitkit/ui/screens/widgets/headlines/HeadlinesPreviewScreen.kt b/app/src/main/java/to/bitkit/ui/screens/widgets/headlines/HeadlinesPreviewScreen.kt index f7d9e2e00..ed2b628b1 100644 --- a/app/src/main/java/to/bitkit/ui/screens/widgets/headlines/HeadlinesPreviewScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/widgets/headlines/HeadlinesPreviewScreen.kt @@ -1,6 +1,5 @@ package to.bitkit.ui.screens.widgets.headlines -import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -37,6 +36,7 @@ fun HeadlinesPreviewScreen( onClose: () -> Unit, onBack: () -> Unit, navigateEditWidget: () -> Unit, + modifier: Modifier = Modifier, ) { val customHeadlinePreferences by headlinesViewModel.customPreferences.collectAsStateWithLifecycle() val article by headlinesViewModel.currentArticle.collectAsStateWithLifecycle() @@ -60,6 +60,7 @@ fun HeadlinesPreviewScreen( headlinesViewModel.savePreferences() onClose() }, + modifier = modifier ) } @@ -72,12 +73,10 @@ fun HeadlinesPreviewContent( isHeadlinesImplemented: Boolean, headlinePreferences: HeadlinePreferences, article: ArticleModel, + modifier: Modifier = Modifier, ) { ScreenColumn( - noBackground = true, - modifier = Modifier - .background(Colors.Gray7) - .testTag("headlines_preview_screen") + modifier = modifier.testTag("headlines_preview_screen") ) { AppTopBar( titleText = stringResource(R.string.widgets__news__name), diff --git a/app/src/main/java/to/bitkit/ui/screens/widgets/price/PriceEditScreen.kt b/app/src/main/java/to/bitkit/ui/screens/widgets/price/PriceEditScreen.kt index 6728b79c3..75af1f960 100644 --- a/app/src/main/java/to/bitkit/ui/screens/widgets/price/PriceEditScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/widgets/price/PriceEditScreen.kt @@ -48,6 +48,7 @@ fun PriceEditScreen( viewModel: PriceViewModel, onBack: () -> Unit, navigatePreview: () -> Unit, + modifier: Modifier = Modifier, ) { val customPreferences by viewModel.customPreferences.collectAsStateWithLifecycle() val isLoading by viewModel.isLoading.collectAsStateWithLifecycle() @@ -60,6 +61,7 @@ fun PriceEditScreen( onSelectTradingPair = { viewModel.selectTradingPair(pair = it) }, onSelectPeriod = { viewModel.setPeriod(period = it) }, isLoading = isLoading, + modifier = modifier ) } @@ -72,14 +74,12 @@ fun PriceEditContent( onClickPreview: () -> Unit, preferences: PricePreferences, isLoading: Boolean, + modifier: Modifier = Modifier, ) { val selectedPair = preferences.enabledPairs.firstOrNull() ?: TradingPair.BTC_USD ScreenColumn( - noBackground = true, - modifier = Modifier - .background(Colors.Gray7) - .testTag("price_edit_screen") + modifier = modifier.testTag("price_edit_screen") ) { Box( modifier = Modifier diff --git a/app/src/main/java/to/bitkit/ui/screens/widgets/price/PricePreviewScreen.kt b/app/src/main/java/to/bitkit/ui/screens/widgets/price/PricePreviewScreen.kt index e1fe0be48..3877bc5ee 100644 --- a/app/src/main/java/to/bitkit/ui/screens/widgets/price/PricePreviewScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/widgets/price/PricePreviewScreen.kt @@ -1,6 +1,5 @@ package to.bitkit.ui.screens.widgets.price -import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -44,6 +43,7 @@ fun PricePreviewScreen( onClose: () -> Unit, onBack: () -> Unit, navigateEditWidget: () -> Unit, + modifier: Modifier = Modifier, ) { val customPricePreferences by priceViewModel.customPreferences.collectAsStateWithLifecycle() val price by priceViewModel.currentPrice.collectAsStateWithLifecycle() @@ -77,6 +77,7 @@ fun PricePreviewScreen( priceViewModel.savePreferences() }, isLoading = isLoading, + modifier = modifier ) } @@ -90,12 +91,10 @@ fun PricePreviewContent( pricePreferences: PricePreferences, priceDTO: PriceDTO?, isLoading: Boolean, + modifier: Modifier = Modifier, ) { ScreenColumn( - noBackground = true, - modifier = Modifier - .background(Colors.Gray7) - .testTag("price_preview_screen") + modifier = modifier.testTag("price_preview_screen") ) { AppTopBar( titleText = stringResource(R.string.widgets__price__name), diff --git a/app/src/main/java/to/bitkit/ui/screens/widgets/weather/WeatherEditScreen.kt b/app/src/main/java/to/bitkit/ui/screens/widgets/weather/WeatherEditScreen.kt index 4790bc2a0..61d675308 100644 --- a/app/src/main/java/to/bitkit/ui/screens/widgets/weather/WeatherEditScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/widgets/weather/WeatherEditScreen.kt @@ -1,6 +1,5 @@ package to.bitkit.ui.screens.widgets.weather -import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -69,10 +68,7 @@ fun WeatherEditContent( modifier: Modifier = Modifier, ) { ScreenColumn( - noBackground = true, - modifier = modifier - .background(Colors.Gray7) - .testTag("weather_edit_screen") + modifier = modifier.testTag("weather_edit_screen") ) { AppTopBar( titleText = stringResource(R.string.widgets__weather__name), diff --git a/app/src/main/java/to/bitkit/ui/screens/widgets/weather/WeatherPreviewScreen.kt b/app/src/main/java/to/bitkit/ui/screens/widgets/weather/WeatherPreviewScreen.kt index d69ebb41b..1dc13223f 100644 --- a/app/src/main/java/to/bitkit/ui/screens/widgets/weather/WeatherPreviewScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/widgets/weather/WeatherPreviewScreen.kt @@ -1,6 +1,5 @@ package to.bitkit.ui.screens.widgets.weather -import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -79,10 +78,7 @@ fun WeatherPreviewContent( modifier: Modifier = Modifier, ) { ScreenColumn( - noBackground = true, - modifier = modifier - .background(Colors.Gray7) - .testTag("weather_preview_screen") + modifier = modifier.testTag("weather_preview_screen") ) { AppTopBar( titleText = stringResource(R.string.widgets__weather__name), diff --git a/app/src/main/res/xml/appwidget_info_blocks.xml b/app/src/main/res/xml/appwidget_info_blocks.xml index 6264f6165..a373fd82c 100644 --- a/app/src/main/res/xml/appwidget_info_blocks.xml +++ b/app/src/main/res/xml/appwidget_info_blocks.xml @@ -13,5 +13,6 @@ android:previewLayout="@layout/appwidget_preview_blocks" android:description="@string/widgets__blocks__description" android:configure="to.bitkit.appwidget.config.AppWidgetConfigActivity" + android:widgetFeatures="reconfigurable" android:updatePeriodMillis="0" tools:targetApi="31" /> diff --git a/app/src/main/res/xml/appwidget_info_headlines.xml b/app/src/main/res/xml/appwidget_info_headlines.xml index e10bf14eb..98eab9286 100644 --- a/app/src/main/res/xml/appwidget_info_headlines.xml +++ b/app/src/main/res/xml/appwidget_info_headlines.xml @@ -13,5 +13,6 @@ android:previewLayout="@layout/appwidget_preview_headlines" android:description="@string/widgets__news__description" android:configure="to.bitkit.appwidget.config.AppWidgetConfigActivity" + android:widgetFeatures="reconfigurable" android:updatePeriodMillis="0" tools:targetApi="31" /> diff --git a/app/src/main/res/xml/appwidget_info_price.xml b/app/src/main/res/xml/appwidget_info_price.xml index 94fe99672..db4c37b04 100644 --- a/app/src/main/res/xml/appwidget_info_price.xml +++ b/app/src/main/res/xml/appwidget_info_price.xml @@ -13,5 +13,6 @@ android:previewLayout="@layout/appwidget_preview_price" android:description="@string/appwidget__price__description" android:configure="to.bitkit.appwidget.config.AppWidgetConfigActivity" + android:widgetFeatures="reconfigurable" android:updatePeriodMillis="0" tools:targetApi="31" /> diff --git a/app/src/main/res/xml/appwidget_info_weather.xml b/app/src/main/res/xml/appwidget_info_weather.xml index 596e504f0..db5b3d58f 100644 --- a/app/src/main/res/xml/appwidget_info_weather.xml +++ b/app/src/main/res/xml/appwidget_info_weather.xml @@ -13,5 +13,6 @@ android:previewLayout="@layout/appwidget_preview_weather" android:description="@string/widgets__weather__description" android:configure="to.bitkit.appwidget.config.AppWidgetConfigActivity" + android:widgetFeatures="reconfigurable" android:updatePeriodMillis="0" tools:targetApi="31" /> diff --git a/app/src/test/java/to/bitkit/data/widgets/PriceServiceTest.kt b/app/src/test/java/to/bitkit/data/widgets/PriceServiceTest.kt new file mode 100644 index 000000000..cdb376cf7 --- /dev/null +++ b/app/src/test/java/to/bitkit/data/widgets/PriceServiceTest.kt @@ -0,0 +1,31 @@ +package to.bitkit.data.widgets + +import org.junit.Test +import java.util.Locale +import kotlin.test.assertEquals +import kotlin.test.assertFalse + +class PriceServiceTest { + + @Test + fun `formatPriceValue excludes currency symbol`() { + val formatted = formatPriceValue(price = 81_444.12, locale = Locale.US) + + assertEquals("81,444", formatted) + assertFalse(formatted.contains('$')) + } + + @Test + fun `formatPriceValue uses provided locale grouping`() { + val formatted = formatPriceValue(price = 81_444.12, locale = Locale.GERMANY) + + assertEquals("81.444", formatted) + } + + @Test + fun `formatPriceValue keeps fractional precision by price range`() { + assertEquals("81,444", formatPriceValue(price = 81_444.12, locale = Locale.US)) + assertEquals("814.12", formatPriceValue(price = 814.12, locale = Locale.US)) + assertEquals("0.123457", formatPriceValue(price = 0.1234567, locale = Locale.US)) + } +} diff --git a/changelog.d/next/936.fixed.md b/changelog.d/next/936.fixed.md new file mode 100644 index 000000000..84f143687 --- /dev/null +++ b/changelog.d/next/936.fixed.md @@ -0,0 +1 @@ +Improves Android widgets so previews, settings, and OS-home interactions match the release behavior.