Skip to content

Commit 0977fb0

Browse files
committed
fix: polish widgets foundation
- fix: simplify widget size carousel - fix: align widget screen backgrounds - fix: color widget config bars - fix: comment out small previews - fix: match widget config system bars - fix: scope widget preview sizes - fix: remove price widget duplicate symbol - fix: add widget release changelog - fix: complete os widget actions - fix: show wide widget previews
1 parent 61cc72c commit 0977fb0

25 files changed

Lines changed: 152 additions & 119 deletions

app/src/androidTest/java/to/bitkit/ui/screens/widgets/headlines/HeadlinesPreviewContentTest.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ class HeadlinesPreviewContentTest {
5858
// Verify settings and preview section
5959
composeTestRule.onNodeWithTag("WidgetEdit").assertExists()
6060
composeTestRule.onNodeWithTag("headlines_preview_carousel").assertExists()
61-
composeTestRule.onNodeWithTag("headline_card_small").assertExists()
61+
composeTestRule.onNodeWithTag("headline_card_wide").assertExists()
6262

6363
// Verify buttons
6464
composeTestRule.onNodeWithTag("buttons_row").assertExists()
@@ -164,7 +164,7 @@ class HeadlinesPreviewContentTest {
164164
composeTestRule.onNodeWithTag("divider").assertExists()
165165
composeTestRule.onNodeWithTag("WidgetEdit").assertExists()
166166
composeTestRule.onNodeWithTag("headlines_preview_carousel").assertExists()
167-
composeTestRule.onNodeWithTag("headline_card_small").assertExists()
167+
composeTestRule.onNodeWithTag("headline_card_wide").assertExists()
168168
composeTestRule.onNodeWithTag("buttons_row").assertExists()
169169
composeTestRule.onNodeWithTag("WidgetDelete").assertExists()
170170
composeTestRule.onNodeWithTag("WidgetSave").assertExists()

app/src/main/java/to/bitkit/appwidget/config/AppWidgetConfigActivity.kt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package to.bitkit.appwidget.config
22

3-
import android.app.Activity
43
import android.appwidget.AppWidgetManager
54
import android.content.Intent
65
import android.os.Bundle
@@ -21,6 +20,7 @@ import to.bitkit.appwidget.ui.price.PriceGlanceWidget
2120
import to.bitkit.appwidget.ui.weather.WeatherGlanceReceiver
2221
import to.bitkit.appwidget.ui.weather.WeatherGlanceWidget
2322
import to.bitkit.ui.theme.AppThemeSurface
23+
import to.bitkit.ui.utils.enableAppEdgeToEdge
2424
import to.bitkit.utils.Logger
2525

2626
@AndroidEntryPoint
@@ -35,6 +35,7 @@ class AppWidgetConfigActivity : ComponentActivity() {
3535

3636
override fun onCreate(savedInstanceState: Bundle?) {
3737
super.onCreate(savedInstanceState)
38+
enableAppEdgeToEdge()
3839

3940
val appWidgetId = intent?.extras?.getInt(
4041
AppWidgetManager.EXTRA_APPWIDGET_ID,
@@ -59,7 +60,9 @@ class AppWidgetConfigActivity : ComponentActivity() {
5960
onConfirm = {
6061
when (viewModel.uiState.value.type) {
6162
AppWidgetType.PRICE -> PriceGlanceWidget().updateAll(this@AppWidgetConfigActivity)
62-
AppWidgetType.HEADLINES -> HeadlinesGlanceWidget().updateAll(this@AppWidgetConfigActivity)
63+
AppWidgetType.HEADLINES -> HeadlinesGlanceWidget().updateAll(
64+
this@AppWidgetConfigActivity,
65+
)
6366
AppWidgetType.BLOCKS -> BlocksGlanceWidget().updateAll(this@AppWidgetConfigActivity)
6467
AppWidgetType.FACTS -> Unit
6568
AppWidgetType.WEATHER -> WeatherGlanceWidget().updateAll(this@AppWidgetConfigActivity)
@@ -70,7 +73,7 @@ class AppWidgetConfigActivity : ComponentActivity() {
7073
AppWidgetManager.EXTRA_APPWIDGET_ID,
7174
appWidgetId,
7275
)
73-
setResult(Activity.RESULT_OK, result)
76+
setResult(RESULT_OK, result)
7477
finish()
7578
},
7679
onCancel = { finish() },

app/src/main/java/to/bitkit/appwidget/config/BlocksConfigContent.kt

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package to.bitkit.appwidget.config
22

33
import androidx.annotation.DrawableRes
4-
import androidx.compose.foundation.background
54
import androidx.compose.foundation.layout.Arrangement
65
import androidx.compose.foundation.layout.Column
76
import androidx.compose.foundation.layout.Row
@@ -61,10 +60,7 @@ internal fun BlocksConfigContent(
6160
)
6261
}
6362

64-
ScreenColumn(
65-
noBackground = true,
66-
modifier = Modifier.background(Colors.Gray7)
67-
) {
63+
ScreenColumn {
6864
AppTopBar(
6965
titleText = stringResource(R.string.widgets__blocks__name),
7066
onBackClick = onCancel,

app/src/main/java/to/bitkit/appwidget/config/HeadlinesConfigContent.kt

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package to.bitkit.appwidget.config
22

3-
import androidx.compose.foundation.background
43
import androidx.compose.foundation.layout.Arrangement
54
import androidx.compose.foundation.layout.Column
65
import androidx.compose.foundation.layout.Row
@@ -43,10 +42,7 @@ internal fun HeadlinesConfigContent(
4342
val prefs = state.headlinePreferences
4443
val previewArticle = state.previewArticle
4544

46-
ScreenColumn(
47-
noBackground = true,
48-
modifier = Modifier.background(Colors.Gray7)
49-
) {
45+
ScreenColumn {
5046
AppTopBar(
5147
titleText = stringResource(R.string.widgets__news__name),
5248
onBackClick = onCancel,

app/src/main/java/to/bitkit/appwidget/config/PriceConfigContent.kt

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package to.bitkit.appwidget.config
22

3-
import androidx.compose.foundation.background
43
import androidx.compose.foundation.clickable
54
import androidx.compose.foundation.layout.Arrangement
65
import androidx.compose.foundation.layout.Column
@@ -44,10 +43,7 @@ internal fun PriceConfigContent(
4443
val prefs = state.pricePreferences
4544
val selectedPair = prefs.enabledPairs.firstOrNull() ?: TradingPair.BTC_USD
4645

47-
ScreenColumn(
48-
noBackground = true,
49-
modifier = Modifier.background(Colors.Gray7)
50-
) {
46+
ScreenColumn {
5147
AppTopBar(
5248
titleText = stringResource(R.string.widgets__price__name),
5349
onBackClick = onCancel,

app/src/main/java/to/bitkit/appwidget/config/WeatherConfigContent.kt

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package to.bitkit.appwidget.config
22

3-
import androidx.compose.foundation.background
43
import androidx.compose.foundation.layout.Arrangement
54
import androidx.compose.foundation.layout.Column
65
import androidx.compose.foundation.layout.Row
@@ -37,15 +36,11 @@ internal fun WeatherConfigContent(
3736
onReset: () -> Unit,
3837
onSave: () -> Unit,
3938
onCancel: () -> Unit,
40-
modifier: Modifier = Modifier,
4139
) {
4240
val prefs = state.weatherPreferences
4341
val weather = state.previewWeather
4442

45-
ScreenColumn(
46-
noBackground = true,
47-
modifier = modifier.background(Colors.Gray7)
48-
) {
43+
ScreenColumn {
4944
AppTopBar(
5045
titleText = stringResource(R.string.widgets__weather__name),
5146
onBackClick = onCancel,

app/src/main/java/to/bitkit/appwidget/ui/facts/FactsGlanceContent.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
package to.bitkit.appwidget.ui.facts
22

3+
import android.content.Intent
34
import androidx.compose.runtime.Composable
45
import androidx.compose.ui.unit.dp
56
import androidx.glance.GlanceModifier
67
import androidx.glance.Image
78
import androidx.glance.ImageProvider
89
import androidx.glance.LocalContext
910
import androidx.glance.LocalSize
11+
import androidx.glance.appwidget.action.actionStartActivity
1012
import androidx.glance.layout.Alignment
1113
import androidx.glance.layout.Box
1214
import androidx.glance.layout.fillMaxSize
@@ -18,6 +20,7 @@ import to.bitkit.appwidget.ui.components.CaptionB
1820
import to.bitkit.appwidget.ui.components.GlanceLayoutDimens
1921
import to.bitkit.appwidget.ui.components.GlanceWidgetScaffold
2022
import to.bitkit.appwidget.ui.theme.GlanceTextStyles
23+
import to.bitkit.ui.MainActivity
2124

2225
private val BADGE_SIZE = 32.dp
2326
private val BADGE_RESERVED_END = 40.dp
@@ -28,8 +31,11 @@ fun FactsGlanceContent(
2831
fact: String?,
2932
) {
3033
val context = LocalContext.current
34+
val openAppIntent = Intent(context, MainActivity::class.java).apply {
35+
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
36+
}
3137

32-
GlanceWidgetScaffold {
38+
GlanceWidgetScaffold(onClick = actionStartActivity(openAppIntent)) {
3339
if (fact == null) {
3440
CaptionB(text = context.getString(R.string.appwidget__loading))
3541
return@GlanceWidgetScaffold

app/src/main/java/to/bitkit/data/widgets/PriceService.kt

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import to.bitkit.models.WidgetType
2222
import to.bitkit.utils.AppError
2323
import to.bitkit.utils.Logger
2424
import java.text.NumberFormat
25-
import java.util.Currency
2625
import java.util.Locale
2726
import javax.inject.Inject
2827
import javax.inject.Singleton
@@ -147,24 +146,15 @@ class PriceService @Inject constructor(
147146
)
148147
}
149148

150-
private fun formatPrice(pair: TradingPair, price: Double): String {
149+
private fun formatPrice(
150+
pair: TradingPair,
151+
price: Double,
152+
locale: Locale = Locale.getDefault(),
153+
): String {
151154
return runCatching {
152-
val currency = Currency.getInstance(pair.quote)
153-
val numberFormat = NumberFormat.getCurrencyInstance(Locale.US).apply {
154-
this.currency = currency
155-
maximumFractionDigits = when {
156-
price >= 1000 -> 0
157-
price >= 1 -> 2
158-
else -> 6
159-
}
160-
}
161-
162-
// Format and remove currency symbol, keeping only the number with formatting
163-
val formatted = numberFormat.format(price)
164-
val currencySymbol = currency.symbol
165-
formatted.replace(currencySymbol, "").trim()
155+
formatPriceValue(price = price, locale = locale)
166156
}.onFailure {
167-
Logger.warn("Error formatting price for ${pair.displayName}", e = it, context = TAG)
157+
Logger.warn("Failed to format price for '${pair.displayName}'", it, context = TAG)
168158
}.getOrDefault(String.format(Locale.US, "%.2f", price))
169159
}
170160

@@ -180,3 +170,25 @@ sealed class PriceError(message: String) : AppError(message) {
180170
class InvalidResponse(override val message: String) : PriceError(message)
181171
class NetworkError(override val message: String) : PriceError(message)
182172
}
173+
174+
private const val GROUPED_PRICE_THRESHOLD = 1_000.0
175+
private const val STANDARD_PRICE_THRESHOLD = 1.0
176+
private const val GROUPED_PRICE_DECIMALS = 0
177+
private const val STANDARD_PRICE_DECIMALS = 2
178+
private const val SMALL_PRICE_DECIMALS = 6
179+
private const val MIN_PRICE_DECIMALS = 0
180+
181+
internal fun formatPriceValue(
182+
price: Double,
183+
locale: Locale = Locale.getDefault(),
184+
): String {
185+
return NumberFormat.getNumberInstance(locale).apply {
186+
maximumFractionDigits = when {
187+
price >= GROUPED_PRICE_THRESHOLD -> GROUPED_PRICE_DECIMALS
188+
price >= STANDARD_PRICE_THRESHOLD -> STANDARD_PRICE_DECIMALS
189+
else -> SMALL_PRICE_DECIMALS
190+
}
191+
minimumFractionDigits = MIN_PRICE_DECIMALS
192+
isGroupingUsed = true
193+
}.format(price)
194+
}

app/src/main/java/to/bitkit/ui/screens/widgets/blocks/BlocksEditScreen.kt

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package to.bitkit.ui.screens.widgets.blocks
22

33
import androidx.annotation.DrawableRes
4-
import androidx.compose.foundation.background
54
import androidx.compose.foundation.layout.Arrangement
65
import androidx.compose.foundation.layout.Column
76
import androidx.compose.foundation.layout.Row
@@ -40,6 +39,7 @@ fun BlocksEditScreen(
4039
blocksViewModel: BlocksViewModel,
4140
onBack: () -> Unit,
4241
navigatePreview: () -> Unit,
42+
modifier: Modifier = Modifier,
4343
) {
4444
val customPreference by blocksViewModel.customPreferences.collectAsStateWithLifecycle()
4545
val currentBlock by blocksViewModel.currentBlock.collectAsStateWithLifecycle()
@@ -67,6 +67,7 @@ fun BlocksEditScreen(
6767
onClickShowSource = { blocksViewModel.toggleShowSource() },
6868
onClickReset = { blocksViewModel.resetCustomPreferences() },
6969
onClickPreview = navigatePreview,
70+
modifier = modifier
7071
)
7172
}
7273

@@ -84,12 +85,10 @@ private fun Content(
8485
onClickPreview: () -> Unit,
8586
blocksPreferences: BlocksPreferences,
8687
block: BlockModel,
88+
modifier: Modifier = Modifier,
8789
) {
8890
ScreenColumn(
89-
noBackground = true,
90-
modifier = Modifier
91-
.background(Colors.Gray7)
92-
.testTag("blocks_edit_screen")
91+
modifier = modifier.testTag("blocks_edit_screen")
9392
) {
9493
AppTopBar(
9594
titleText = stringResource(R.string.widgets__blocks__name),

app/src/main/java/to/bitkit/ui/screens/widgets/blocks/BlocksPreviewScreen.kt

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package to.bitkit.ui.screens.widgets.blocks
22

3-
import androidx.compose.foundation.background
43
import androidx.compose.foundation.layout.Arrangement
54
import androidx.compose.foundation.layout.Column
65
import androidx.compose.foundation.layout.Row
@@ -37,6 +36,7 @@ fun BlocksPreviewScreen(
3736
onClose: () -> Unit,
3837
onBack: () -> Unit,
3938
navigateEditWidget: () -> Unit,
39+
modifier: Modifier = Modifier,
4040
) {
4141
val customBlocksPreferences by blocksViewModel.customPreferences.collectAsStateWithLifecycle()
4242
val currentBlock by blocksViewModel.currentBlock.collectAsStateWithLifecycle()
@@ -60,6 +60,7 @@ fun BlocksPreviewScreen(
6060
blocksViewModel.savePreferences()
6161
onClose()
6262
},
63+
modifier = modifier
6364
)
6465
}
6566

@@ -72,12 +73,10 @@ private fun Content(
7273
isBlocksWidgetEnabled: Boolean,
7374
blocksPreferences: BlocksPreferences,
7475
block: BlockModel?,
76+
modifier: Modifier = Modifier,
7577
) {
7678
ScreenColumn(
77-
noBackground = true,
78-
modifier = Modifier
79-
.background(Colors.Gray7)
80-
.testTag("blocks_preview_screen")
79+
modifier = modifier.testTag("blocks_preview_screen")
8180
) {
8281
AppTopBar(
8382
titleText = stringResource(R.string.widgets__blocks__name),

0 commit comments

Comments
 (0)