From 59cbdba58bb46f0ea2a8de017e67f652edb6098b Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Wed, 18 Feb 2026 13:03:23 -0300 Subject: [PATCH 01/32] chore: add widgetsOnboardingHintDismissed flag --- app/src/main/java/to/bitkit/data/SettingsStore.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/to/bitkit/data/SettingsStore.kt b/app/src/main/java/to/bitkit/data/SettingsStore.kt index a3cfcef84..0c9fd240f 100644 --- a/app/src/main/java/to/bitkit/data/SettingsStore.kt +++ b/app/src/main/java/to/bitkit/data/SettingsStore.kt @@ -113,6 +113,7 @@ data class SettingsData( val backupWarningIgnoredMillis: Long = 0, val notificationsIgnoredMillis: Long = 0, val balanceWarningTimes: Int = 0, + val widgetsOnboardingHintDismissed: Boolean = false, val coinSelectAuto: Boolean = true, val coinSelectPreference: CoinSelectionPreference = CoinSelectionPreference.BranchAndBound, val electrumServer: String = Env.electrumServerUrl, From 7256873fad883fa529b201dd6edbda9d1b7f0230 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Wed, 18 Feb 2026 13:03:50 -0300 Subject: [PATCH 02/32] feat: update HomeUiState with new fields --- app/src/main/java/to/bitkit/ui/screens/wallets/HomeUiState.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeUiState.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeUiState.kt index 7b086e64e..61530826f 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeUiState.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeUiState.kt @@ -36,4 +36,6 @@ data class HomeUiState( val isEditingWidgets: Boolean = false, val deleteWidgetAlert: WidgetType? = null, val showEmptyState: Boolean = false, + val currentPage: Int = 0, + val showWidgetsOnboardingHint: Boolean = false, ) From 7c813a38e709ca1f65975f84a1dbfdaca895c3c1 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Wed, 18 Feb 2026 13:06:16 -0300 Subject: [PATCH 03/32] feat: update HomeViewModel with page tracking and hint logic --- .../to/bitkit/ui/screens/wallets/HomeViewModel.kt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeViewModel.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeViewModel.kt index 5410ad6e3..483aa53c8 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeViewModel.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeViewModel.kt @@ -71,6 +71,8 @@ class HomeViewModel @Inject constructor( currentBlock = widgetsData.block?.toBlockModel(), currentWeather = widgetsData.weather?.toWeatherModel(), currentPrice = widgetsData.price, + showWidgetsOnboardingHint = settings.showWidgets && + !settings.widgetsOnboardingHintDismissed, ) }.collect { newState -> _uiState.update { newState } @@ -142,6 +144,16 @@ class HomeViewModel @Inject constructor( _currentFact.value = null } + fun onPageChanged(page: Int) { + _uiState.update { it.copy(currentPage = page) } + } + + fun dismissWidgetsOnboardingHint() { + viewModelScope.launch { + settingsStore.update { it.copy(widgetsOnboardingHintDismissed = true) } + } + } + fun dismissEmptyState() { viewModelScope.launch { settingsStore.update { it.copy(showEmptyBalanceView = false) } From 49fabc587009bda705185d49fb8fd9553e063268 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Wed, 18 Feb 2026 13:06:46 -0300 Subject: [PATCH 04/32] chore: simplify ActivityListSimple --- .../activity/components/ActivityListSimple.kt | 42 ++++++------------- 1 file changed, 12 insertions(+), 30 deletions(-) diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/activity/components/ActivityListSimple.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/activity/components/ActivityListSimple.kt index cc476b42a..a8aa4f75f 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/activity/components/ActivityListSimple.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/activity/components/ActivityListSimple.kt @@ -23,28 +23,24 @@ fun ActivityListSimple( items: List?, onAllActivityClick: () -> Unit, onActivityItemClick: (String) -> Unit, - onEmptyActivityRowClick: () -> Unit, ) { + if (items.isNullOrEmpty()) return Column( horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.fillMaxWidth() ) { - if (items != null && items.isNotEmpty()) { - items.forEachIndexed { index, item -> - ActivityRow(item, onActivityItemClick, testTag = "ActivityShort-$index") - VerticalSpacer(16.dp) - } - TertiaryButton( - text = stringResource(R.string.wallet__activity_show_all), - onClick = onAllActivityClick, - modifier = Modifier - .wrapContentWidth() - .padding(top = 8.dp) - .testTag("ActivityShowAll") - ) - } else { - EmptyActivityRow(onClick = onEmptyActivityRowClick) + items.forEachIndexed { index, item -> + ActivityRow(item, onActivityItemClick, testTag = "ActivityShort-$index") + VerticalSpacer(16.dp) } + TertiaryButton( + text = stringResource(R.string.wallet__activity_show_all), + onClick = onAllActivityClick, + modifier = Modifier + .wrapContentWidth() + .padding(top = 8.dp) + .testTag("ActivityShowAll") + ) } } @@ -56,20 +52,6 @@ private fun Preview() { items = previewActivityItems, onAllActivityClick = {}, onActivityItemClick = {}, - onEmptyActivityRowClick = {}, - ) - } -} - -@Preview -@Composable -private fun PreviewEmpty() { - AppThemeSurface { - ActivityListSimple( - items = emptyList(), - onAllActivityClick = {}, - onActivityItemClick = {}, - onEmptyActivityRowClick = {}, ) } } From c81eb53dd465aebdd45618db6f4cbef5e46d12e9 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Wed, 18 Feb 2026 13:08:01 -0300 Subject: [PATCH 05/32] chore: add string resources and drawable --- app/src/main/res/drawable/ic_swipe_hint.xml | 9 +++++++++ app/src/main/res/values/strings.xml | 1 + 2 files changed, 10 insertions(+) create mode 100644 app/src/main/res/drawable/ic_swipe_hint.xml diff --git a/app/src/main/res/drawable/ic_swipe_hint.xml b/app/src/main/res/drawable/ic_swipe_hint.xml new file mode 100644 index 000000000..5e60113a9 --- /dev/null +++ b/app/src/main/res/drawable/ic_swipe_hint.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0d080f226..fe6601bee 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1000,4 +1000,5 @@ Widget Source Widgets + Swipe down\nto find your\nwidgets From 764a92f78c37d6fc79e6d1936210e54ff592e594 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Wed, 18 Feb 2026 13:22:50 -0300 Subject: [PATCH 06/32] feat: restructure HomeScreen with VerticalPager --- .../bitkit/ui/screens/wallets/HomeScreen.kt | 478 +++++++++++------- 1 file changed, 305 insertions(+), 173 deletions(-) diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt index 5367f742f..a39a98ed7 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt @@ -9,17 +9,19 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.IntrinsicSize import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.statusBars import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.pager.VerticalPager +import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.DrawerState @@ -44,6 +46,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource @@ -75,7 +78,9 @@ import to.bitkit.ui.Routes import to.bitkit.ui.components.ActivityBanner import to.bitkit.ui.components.AppStatus import to.bitkit.ui.components.BalanceHeaderView +import to.bitkit.ui.components.Display import to.bitkit.ui.components.EmptyStateView +import to.bitkit.ui.components.FillHeight import to.bitkit.ui.components.HorizontalSpacer import to.bitkit.ui.components.Sheet import to.bitkit.ui.components.StatusBarSpacer @@ -114,6 +119,10 @@ import to.bitkit.viewmodels.AppViewModel import to.bitkit.viewmodels.SettingsViewModel import to.bitkit.viewmodels.WalletViewModel +private const val SMALL_SCREEN_HEIGHT_DP = 700 +private const val SMALL_SCREEN_ACTIVITY_COUNT = 2 +private const val LARGE_SCREEN_ACTIVITY_COUNT = 3 + @Suppress("CyclomaticComplexMethod") @Composable fun HomeScreen( @@ -130,7 +139,6 @@ fun HomeScreen( val context = LocalContext.current val hasSeenTransferIntro by settingsViewModel.hasSeenTransferIntro.collectAsStateWithLifecycle() val hasSeenShopIntro by settingsViewModel.hasSeenShopIntro.collectAsStateWithLifecycle() - val hasSeenProfileIntro by settingsViewModel.hasSeenProfileIntro.collectAsStateWithLifecycle() val hasSeenWidgetsIntro: Boolean by settingsViewModel.hasSeenWidgetsIntro.collectAsStateWithLifecycle() val bgPaymentsIntroSeen: Boolean by settingsViewModel.bgPaymentsIntroSeen.collectAsStateWithLifecycle() val quickPayIntroSeen by settingsViewModel.quickPayIntroSeen.collectAsStateWithLifecycle() @@ -256,8 +264,8 @@ fun HomeScreen( onMoveWidget = { fromIndex, toIndex -> homeViewModel.moveWidget(fromIndex, toIndex) }, - onDismissEmptyState = homeViewModel::dismissEmptyState, - onClickEmptyActivityRow = { appViewModel.showSheet(Sheet.Receive) }, + onPageChanged = homeViewModel::onPageChanged, + onDismissWidgetsOnboardingHint = homeViewModel::dismissWidgetsOnboardingHint, ) } @@ -280,192 +288,159 @@ private fun Content( onClickEditWidget: (WidgetType) -> Unit = {}, onClickDeleteWidget: (WidgetType) -> Unit = {}, onMoveWidget: (Int, Int) -> Unit = { _, _ -> }, - onDismissEmptyState: () -> Unit = {}, - onClickEmptyActivityRow: () -> Unit = {}, + onPageChanged: (Int) -> Unit = {}, + onDismissWidgetsOnboardingHint: () -> Unit = {}, balances: BalanceState = LocalBalances.current, ) { val scope = rememberCoroutineScope() + val pageCount = if (homeUiState.showWidgets) 2 else 1 + val pagerState = rememberPagerState(pageCount = { pageCount }) + + LaunchedEffect(pagerState.currentPage) { + onPageChanged(pagerState.currentPage) + if (pagerState.currentPage == 1 && !latestActivities.isNullOrEmpty()) { + onDismissWidgetsOnboardingHint() + } + } + + val screenHeightDp = LocalConfiguration.current.screenHeightDp + val activityCount = if (screenHeightDp < SMALL_SCREEN_HEIGHT_DP) { + SMALL_SCREEN_ACTIVITY_COUNT + } else { + LARGE_SCREEN_ACTIVITY_COUNT + } Box { - val heightStatusBar = WindowInsets.statusBars.asPaddingValues().calculateTopPadding() TopBar( hazeState = hazeState, rootNavController = rootNavController, scope = scope, drawerState = drawerState, + showEditWidgets = homeUiState.currentPage == 1 && homeUiState.showWidgets, + isEditingWidgets = homeUiState.isEditingWidgets, + onClickEditWidgetList = onClickEditWidgetList, ) - val pullToRefreshState = rememberPullToRefreshState() - PullToRefreshBox( - state = pullToRefreshState, - isRefreshing = isRefreshing, - onRefresh = onRefresh, - indicator = { - Indicator( - isRefreshing = isRefreshing, - state = pullToRefreshState, - modifier = Modifier - .padding(top = heightStatusBar) - .align(Alignment.TopCenter) - ) - }, + + VerticalPager( + state = pagerState, + userScrollEnabled = homeUiState.showWidgets, modifier = Modifier .fillMaxSize() .hazeSource(state = hazeState) .zIndex(0f) - ) { - Column( - modifier = Modifier - .padding(horizontal = 16.dp) - .fillMaxSize() - .verticalScroll(rememberScrollState()) - .testTag("HomeScrollView") - ) { - StatusBarSpacer() - TopBarSpacer() - VerticalSpacer(16.dp) - BalanceHeaderView( - sats = balances.totalSats.toLong(), - showEyeIcon = true, - testTag = "TotalBalance", - modifier = Modifier - .fillMaxWidth() - .testTag("TotalBalance") + ) { page -> + when (page) { + 0 -> WalletPage( + isRefreshing = isRefreshing, + homeUiState = homeUiState, + latestActivities = latestActivities?.take(activityCount), + balances = balances, + rootNavController = rootNavController, + walletNavController = walletNavController, + onRefresh = onRefresh, ) - if (!homeUiState.showEmptyState) { - Spacer(modifier = Modifier.height(32.dp)) - Row( - modifier = Modifier - .fillMaxWidth() - .height(IntrinsicSize.Min) - ) { - WalletBalanceView( - title = stringResource(R.string.wallet__savings__title), - sats = balances.totalOnchainSats.toLong(), - icon = painterResource(id = R.drawable.ic_btc_circle), - modifier = Modifier - .clickableAlpha { walletNavController.navigate(Routes.Savings) } - .padding(vertical = 4.dp) - .testTag("ActivitySavings") - ) - VerticalDivider() - HorizontalSpacer(16.dp) - WalletBalanceView( - title = stringResource(R.string.wallet__spending__title), - sats = balances.totalLightningSats.toLong(), - icon = painterResource(id = R.drawable.ic_ln_circle), - modifier = Modifier - .clickableAlpha { walletNavController.navigate(Routes.Spending) } - .padding(vertical = 4.dp) - .testTag("ActivitySpending") - ) - } - - AnimatedVisibility(homeUiState.suggestions.isNotEmpty()) { - val state = rememberLazyListState() - val snapBehavior = rememberSnapFlingBehavior( - lazyListState = state, - snapPosition = SnapPosition.Start - ) - Column { - Spacer(modifier = Modifier.height(32.dp)) - Text13Up(stringResource(R.string.cards__suggestions), color = Colors.White64) - Spacer(modifier = Modifier.height(16.dp)) - LazyRow( - horizontalArrangement = Arrangement.spacedBy(16.dp), - state = state, - flingBehavior = snapBehavior, - modifier = Modifier - .fillMaxWidth() - .testTag("Suggestions") - ) { - items(homeUiState.suggestions, key = { it.name }) { item -> - SuggestionCard( - gradientColor = item.color, - title = stringResource(item.title), - description = stringResource(item.description), - icon = item.icon, - onClose = { onRemoveSuggestion(item) }.takeIf { item.dismissible }, - onClick = { onClickSuggestion(item) }, - modifier = Modifier.testTag("Suggestion-${item.name.lowercase()}") - ) - } - } - } - } + 1 -> WidgetsPage( + homeUiState = homeUiState, + onRemoveSuggestion = onRemoveSuggestion, + onClickSuggestion = onClickSuggestion, + onClickAddWidget = onClickAddWidget, + onClickEditWidget = onClickEditWidget, + onClickDeleteWidget = onClickDeleteWidget, + onMoveWidget = onMoveWidget, + ) + } + } + } +} - if (homeUiState.showWidgets) { - Spacer(modifier = Modifier.height(32.dp)) - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically - ) { - Text13Up( - stringResource(R.string.widgets__widgets), - color = Colors.White64 - ) - - IconButton( - onClick = onClickEditWidgetList, - modifier = Modifier.testTag("WidgetsEdit") - ) { - Icon( - painter = when (homeUiState.isEditingWidgets) { - true -> painterResource(R.drawable.ic_check) - else -> painterResource(R.drawable.ic_sort_ascending) - }, - contentDescription = null, - ) - } - } +@Suppress("MagicNumber") +@OptIn(ExperimentalMaterial3Api::class) +@Composable +private fun WalletPage( + isRefreshing: Boolean, + homeUiState: HomeUiState, + latestActivities: List?, + balances: BalanceState, + rootNavController: NavController, + walletNavController: NavController, + onRefresh: () -> Unit, +) { + val heightStatusBar = WindowInsets.statusBars.asPaddingValues().calculateTopPadding() + val pullToRefreshState = rememberPullToRefreshState() + val hasActivity = !latestActivities.isNullOrEmpty() - Spacer(modifier = Modifier.height(16.dp)) - - if (homeUiState.isEditingWidgets) { - DragDropColumn( - items = homeUiState.widgetsWithPosition, - onMove = onMoveWidget, - modifier = Modifier.fillMaxWidth() - ) { widgetWithPosition, isDragging -> - DragAndDropWidget( - iconRes = widgetWithPosition.type.iconRes, - title = stringResource(widgetWithPosition.type.title), - onClickSettings = { onClickEditWidget(widgetWithPosition.type) }, - onClickDelete = { onClickDeleteWidget(widgetWithPosition.type) }, - modifier = Modifier - .fillMaxWidth() - .graphicsLayer { - alpha = if (isDragging) 0.8f else 1.0f - } - ) - } - } else { - Widgets(homeUiState) - } + PullToRefreshBox( + state = pullToRefreshState, + isRefreshing = isRefreshing, + onRefresh = onRefresh, + indicator = { + Indicator( + isRefreshing = isRefreshing, + state = pullToRefreshState, + modifier = Modifier + .padding(top = heightStatusBar) + .align(Alignment.TopCenter) + ) + }, + modifier = Modifier.fillMaxSize() + ) { + Column( + modifier = Modifier + .padding(horizontal = 16.dp) + .fillMaxSize() + .verticalScroll(rememberScrollState()) + .testTag("HomeScrollView") + ) { + StatusBarSpacer() + TopBarSpacer() + VerticalSpacer(16.dp) + + BalanceHeaderView( + sats = balances.totalSats.toLong(), + showEyeIcon = true, + testTag = "TotalBalance", + modifier = Modifier + .fillMaxWidth() + .testTag("TotalBalance") + ) - Spacer(modifier = Modifier.height(32.dp)) - TertiaryButton( - text = stringResource(R.string.widgets__add), - icon = { - Icon( - painter = painterResource(R.drawable.ic_plus), - contentDescription = null, - tint = Colors.White80, - ) - }, - onClick = onClickAddWidget, - modifier = Modifier.testTag("WidgetsAdd") - ) - } - Spacer(modifier = Modifier.height(32.dp)) + if (!homeUiState.showEmptyState) { + VerticalSpacer(32.dp) + Row( + modifier = Modifier + .fillMaxWidth() + .height(IntrinsicSize.Min) + ) { + WalletBalanceView( + title = stringResource(R.string.wallet__savings__title), + sats = balances.totalOnchainSats.toLong(), + icon = painterResource(id = R.drawable.ic_btc_circle), + modifier = Modifier + .clickableAlpha { walletNavController.navigate(Routes.Savings) } + .padding(vertical = 4.dp) + .testTag("ActivitySavings") + ) + VerticalDivider() + HorizontalSpacer(16.dp) + WalletBalanceView( + title = stringResource(R.string.wallet__spending__title), + sats = balances.totalLightningSats.toLong(), + icon = painterResource(id = R.drawable.ic_ln_circle), + modifier = Modifier + .clickableAlpha { walletNavController.navigate(Routes.Spending) } + .padding(vertical = 4.dp) + .testTag("ActivitySpending") + ) + } + if (hasActivity) { AnimatedVisibility(homeUiState.banners.isNotEmpty()) { Column( verticalArrangement = Arrangement.spacedBy(16.dp), modifier = Modifier .fillMaxWidth() - .padding(bottom = 18.dp) + .padding(top = 32.dp, bottom = 18.dp) ) { homeUiState.banners.forEach { banner -> ActivityBanner( @@ -474,7 +449,8 @@ private fun Content( icon = banner.icon, onClick = { when (banner) { - ActivityBannerType.SPENDING -> rootNavController.navigate(Routes.SettingUp) + ActivityBannerType.SPENDING -> + rootNavController.navigate(Routes.SettingUp) ActivityBannerType.SAVINGS -> Unit } }, @@ -484,26 +460,164 @@ private fun Content( } } + VerticalSpacer(32.dp) + ActivityListSimple( items = latestActivities, onAllActivityClick = { rootNavController.navigateToAllActivity() }, onActivityItemClick = { rootNavController.navigateToActivityItem(it) }, - onEmptyActivityRowClick = onClickEmptyActivityRow, ) - VerticalSpacer(150.dp) // scrollable empty space behind footer + FillHeight() + + if (homeUiState.showWidgetsOnboardingHint) { + WidgetsOnboardingHint() + } } + + VerticalSpacer(150.dp) } - if (homeUiState.showEmptyState) { - EmptyStateView( - text = stringResource(R.string.onboarding__empty_wallet).withAccent(), - onClose = onDismissEmptyState, + } + + if (homeUiState.showEmptyState) { + EmptyStateView( + text = stringResource(R.string.onboarding__empty_wallet).withAccent(), + modifier = Modifier + .align(Alignment.BottomCenter) + .padding(bottom = 24.dp) + ) + } + } +} + +@Suppress("MagicNumber") +@Composable +private fun WidgetsPage( + homeUiState: HomeUiState, + onRemoveSuggestion: (Suggestion) -> Unit, + onClickSuggestion: (Suggestion) -> Unit, + onClickAddWidget: () -> Unit, + onClickEditWidget: (WidgetType) -> Unit, + onClickDeleteWidget: (WidgetType) -> Unit, + onMoveWidget: (Int, Int) -> Unit, +) { + Column( + modifier = Modifier + .padding(horizontal = 16.dp) + .fillMaxSize() + .verticalScroll(rememberScrollState()) + ) { + StatusBarSpacer() + TopBarSpacer() + VerticalSpacer(16.dp) + + AnimatedVisibility(homeUiState.suggestions.isNotEmpty()) { + SuggestionsSection( + suggestions = homeUiState.suggestions, + onRemoveSuggestion = onRemoveSuggestion, + onClickSuggestion = onClickSuggestion, + ) + } + + if (homeUiState.isEditingWidgets) { + DragDropColumn( + items = homeUiState.widgetsWithPosition, + onMove = onMoveWidget, + modifier = Modifier.fillMaxWidth() + ) { widgetWithPosition, isDragging -> + DragAndDropWidget( + iconRes = widgetWithPosition.type.iconRes, + title = stringResource(widgetWithPosition.type.title), + onClickSettings = { onClickEditWidget(widgetWithPosition.type) }, + onClickDelete = { onClickDeleteWidget(widgetWithPosition.type) }, modifier = Modifier - .align(Alignment.BottomCenter) - .padding(bottom = 24.dp) + .fillMaxWidth() + .graphicsLayer { + alpha = if (isDragging) 0.8f else 1.0f + } ) } + } else { + Widgets(homeUiState) } + + VerticalSpacer(32.dp) + + TertiaryButton( + text = stringResource(R.string.widgets__add), + icon = { + Icon( + painter = painterResource(R.drawable.ic_plus), + contentDescription = null, + tint = Colors.White80, + ) + }, + onClick = onClickAddWidget, + modifier = Modifier.testTag("WidgetsAdd") + ) + + VerticalSpacer(150.dp) + } +} + +@Composable +private fun SuggestionsSection( + suggestions: List, + onRemoveSuggestion: (Suggestion) -> Unit, + onClickSuggestion: (Suggestion) -> Unit, + modifier: Modifier = Modifier, +) { + val state = rememberLazyListState() + val snapBehavior = rememberSnapFlingBehavior( + lazyListState = state, + snapPosition = SnapPosition.Start + ) + + Column(modifier = modifier.padding(bottom = 32.dp)) { + Text13Up(stringResource(R.string.cards__suggestions), color = Colors.White64) + VerticalSpacer(16.dp) + LazyRow( + horizontalArrangement = Arrangement.spacedBy(16.dp), + state = state, + flingBehavior = snapBehavior, + modifier = Modifier + .fillMaxWidth() + .testTag("Suggestions") + ) { + items(suggestions, key = { it.name }) { item -> + SuggestionCard( + gradientColor = item.color, + title = stringResource(item.title), + description = stringResource(item.description), + icon = item.icon, + onClose = { onRemoveSuggestion(item) }.takeIf { item.dismissible }, + onClick = { onClickSuggestion(item) }, + modifier = Modifier.testTag("Suggestion-${item.name.lowercase()}") + ) + } + } + } +} + +@Composable +private fun WidgetsOnboardingHint(modifier: Modifier = Modifier) { + Row( + verticalAlignment = Alignment.Bottom, + modifier = modifier + .fillMaxWidth() + .padding(vertical = 32.dp) + ) { + Display( + text = stringResource(R.string.widgets__onboarding_swipe).withAccent(), + modifier = Modifier.weight(1f) + ) + HorizontalSpacer(16.dp) + Icon( + painter = painterResource(R.drawable.ic_swipe_hint), + contentDescription = null, + tint = Colors.White64, + modifier = Modifier.size(40.dp) + ) } } @@ -611,6 +725,9 @@ private fun TopBar( rootNavController: NavController, scope: CoroutineScope, drawerState: DrawerState, + showEditWidgets: Boolean = false, + isEditingWidgets: Boolean = false, + onClickEditWidgetList: () -> Unit = {}, ) { val topbarGradient = Brush.verticalGradient( colorStops = arrayOf( @@ -631,6 +748,21 @@ private fun TopBar( TopAppBar( title = {}, actions = { + if (showEditWidgets) { + IconButton( + onClick = onClickEditWidgetList, + modifier = Modifier.testTag("WidgetsEdit") + ) { + Icon( + painter = if (isEditingWidgets) { + painterResource(R.drawable.ic_check) + } else { + painterResource(R.drawable.ic_sort_ascending) + }, + contentDescription = null, + ) + } + } AppStatus(onClick = { rootNavController.navigate(Routes.AppStatus) }) HorizontalSpacer(4.dp) IconButton( From 0dc1ddb0e508767848ba7b3a9bfd5a043396c516 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Wed, 18 Feb 2026 13:44:04 -0300 Subject: [PATCH 07/32] feat: change SuggestionCard to use aspectRatio instead of fixed size --- app/src/main/java/to/bitkit/ui/components/SuggestionCard.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/to/bitkit/ui/components/SuggestionCard.kt b/app/src/main/java/to/bitkit/ui/components/SuggestionCard.kt index 8c1a36fb8..cf1dd72c1 100644 --- a/app/src/main/java/to/bitkit/ui/components/SuggestionCard.kt +++ b/app/src/main/java/to/bitkit/ui/components/SuggestionCard.kt @@ -13,6 +13,7 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding @@ -54,7 +55,6 @@ fun SuggestionCard( description: String, @DrawableRes icon: Int, onClose: (() -> Unit)? = null, - size: Int = 152, disableGlow: Boolean = false, captionColor: Color = Colors.White64, onClick: () -> Unit, @@ -75,7 +75,8 @@ fun SuggestionCard( Box( modifier = modifier - .size(size.dp) + .fillMaxWidth() + .aspectRatio(1f) .clip(ShapeDefaults.Large) .then( if (isDismissible || disableGlow) { From f58a28807d6b99b93799affa04242e5efa573dc2 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Wed, 18 Feb 2026 13:49:24 -0300 Subject: [PATCH 08/32] feat: convert suggestion list into a grid --- .../bitkit/ui/screens/wallets/HomeScreen.kt | 68 +++++++++++-------- .../ui/screens/wallets/HomeViewModel.kt | 7 +- 2 files changed, 46 insertions(+), 29 deletions(-) diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt index a39a98ed7..e3688a12f 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt @@ -1,11 +1,11 @@ package to.bitkit.ui.screens.wallets import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.core.tween import androidx.compose.foundation.background -import androidx.compose.foundation.gestures.snapping.SnapPosition -import androidx.compose.foundation.gestures.snapping.rememberSnapFlingBehavior import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.IntrinsicSize import androidx.compose.foundation.layout.Row @@ -17,9 +17,9 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.statusBars -import androidx.compose.foundation.lazy.LazyRow -import androidx.compose.foundation.lazy.items -import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.foundation.lazy.grid.items import androidx.compose.foundation.pager.VerticalPager import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.foundation.rememberScrollState @@ -122,6 +122,7 @@ import to.bitkit.viewmodels.WalletViewModel private const val SMALL_SCREEN_HEIGHT_DP = 700 private const val SMALL_SCREEN_ACTIVITY_COUNT = 2 private const val LARGE_SCREEN_ACTIVITY_COUNT = 3 +private const val ANIMATION_DURATION_MS = 300 @Suppress("CyclomaticComplexMethod") @Composable @@ -567,33 +568,44 @@ private fun SuggestionsSection( onClickSuggestion: (Suggestion) -> Unit, modifier: Modifier = Modifier, ) { - val state = rememberLazyListState() - val snapBehavior = rememberSnapFlingBehavior( - lazyListState = state, - snapPosition = SnapPosition.Start - ) + val rows = (suggestions.size + 1) / 2 Column(modifier = modifier.padding(bottom = 32.dp)) { Text13Up(stringResource(R.string.cards__suggestions), color = Colors.White64) VerticalSpacer(16.dp) - LazyRow( - horizontalArrangement = Arrangement.spacedBy(16.dp), - state = state, - flingBehavior = snapBehavior, - modifier = Modifier - .fillMaxWidth() - .testTag("Suggestions") - ) { - items(suggestions, key = { it.name }) { item -> - SuggestionCard( - gradientColor = item.color, - title = stringResource(item.title), - description = stringResource(item.description), - icon = item.icon, - onClose = { onRemoveSuggestion(item) }.takeIf { item.dismissible }, - onClick = { onClickSuggestion(item) }, - modifier = Modifier.testTag("Suggestion-${item.name.lowercase()}") - ) + BoxWithConstraints(modifier = Modifier.fillMaxWidth()) { + val cardSize = (maxWidth - 16.dp) / 2 + val gridHeight = (cardSize * rows) + (16.dp * (rows - 1)) + LazyVerticalGrid( + columns = GridCells.Fixed(2), + horizontalArrangement = Arrangement.spacedBy(16.dp), + verticalArrangement = Arrangement.spacedBy(16.dp), + userScrollEnabled = false, + modifier = Modifier + .fillMaxWidth() + .height(gridHeight) + .testTag("Suggestions") + ) { + items( + items = suggestions, + key = { it.name } + ) { item -> + SuggestionCard( + gradientColor = item.color, + title = stringResource(item.title), + description = stringResource(item.description), + icon = item.icon, + onClose = { onRemoveSuggestion(item) }.takeIf { item.dismissible }, + onClick = { onClickSuggestion(item) }, + modifier = Modifier + .testTag("Suggestion-${item.name.lowercase()}") + .animateItem( + fadeInSpec = tween(durationMillis = ANIMATION_DURATION_MS), + fadeOutSpec = tween(durationMillis = ANIMATION_DURATION_MS), + placementSpec = tween(durationMillis = ANIMATION_DURATION_MS), + ) + ) + } } } } diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeViewModel.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeViewModel.kt index 483aa53c8..5302c2b40 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeViewModel.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeViewModel.kt @@ -291,6 +291,11 @@ class HomeViewModel @Inject constructor( } } val dismissedList = settings.dismissedSuggestions.mapNotNull { it.toSuggestionOrNull() } - baseSuggestions.filterNot { it in dismissedList } + baseSuggestions.filterNot { it in dismissedList }.take(MAX_SUGGESTIONS) + } + + companion object { + private const val TAG = "HomeViewModel" + private const val MAX_SUGGESTIONS = 4 } } From 6db1be5afcd96df3ec387f27979b1a087f716eeb Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Wed, 18 Feb 2026 13:52:46 -0300 Subject: [PATCH 09/32] feat: add Suggestions entry to AddWidgetsScreen --- .../bitkit/ui/screens/widgets/AddWidgetsScreen.kt | 13 ++++++++++++- app/src/main/res/values/strings.xml | 2 ++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/to/bitkit/ui/screens/widgets/AddWidgetsScreen.kt b/app/src/main/java/to/bitkit/ui/screens/widgets/AddWidgetsScreen.kt index 300d8a5d3..e8fb45242 100644 --- a/app/src/main/java/to/bitkit/ui/screens/widgets/AddWidgetsScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/widgets/AddWidgetsScreen.kt @@ -19,6 +19,7 @@ import to.bitkit.ui.theme.AppThemeSurface @Composable fun AddWidgetsScreen( onWidgetSelected: (WidgetType) -> Unit, + onSuggestionsClick: () -> Unit, onBackCLick: () -> Unit, fiatSymbol: String, ) { @@ -32,6 +33,15 @@ fun AddWidgetsScreen( Column( modifier = Modifier.padding(horizontal = 16.dp) ) { + SettingsButtonRow( + title = stringResource(R.string.widgets__suggestions__name), + subtitle = stringResource(R.string.widgets__suggestions__description), + iconRes = R.drawable.widget_suggestions, + iconSize = 48.dp, + maxLinesSubtitle = 1, + onClick = onSuggestionsClick, + modifier = Modifier.testTag("WidgetListItem-suggestions") + ) SettingsButtonRow( title = stringResource(R.string.widgets__price__name), subtitle = stringResource(R.string.widgets__price__description), @@ -100,8 +110,9 @@ private fun Preview() { AppThemeSurface { AddWidgetsScreen( onWidgetSelected = {}, + onSuggestionsClick = {}, fiatSymbol = "$", - onBackCLick = {} + onBackCLick = {}, ) } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index fe6601bee..5f4832314 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1001,4 +1001,6 @@ Source Widgets Swipe down\nto find your\nwidgets + Discover everything Bitkit has to offer. + Bitkit Suggestions From 7cf6cd169858af3260b5490bbfe4e9643ddc9dca Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Wed, 18 Feb 2026 13:59:16 -0300 Subject: [PATCH 10/32] feat: create SuggestionsPreviewScreen and wire navigation --- app/src/main/java/to/bitkit/ui/ContentView.kt | 13 +- .../shop/shopDiscover/ShopDiscoverScreen.kt | 10 +- .../suggestions/SuggestionsPreviewScreen.kt | 146 ++++++++++++++++++ .../main/res/drawable/widget_suggestions.xml | 20 +++ 4 files changed, 183 insertions(+), 6 deletions(-) create mode 100644 app/src/main/java/to/bitkit/ui/screens/widgets/suggestions/SuggestionsPreviewScreen.kt create mode 100644 app/src/main/res/drawable/widget_suggestions.xml diff --git a/app/src/main/java/to/bitkit/ui/ContentView.kt b/app/src/main/java/to/bitkit/ui/ContentView.kt index 45ae8f1d5..de420783d 100644 --- a/app/src/main/java/to/bitkit/ui/ContentView.kt +++ b/app/src/main/java/to/bitkit/ui/ContentView.kt @@ -105,6 +105,7 @@ import to.bitkit.ui.screens.wallets.activity.TagSelectorSheet import to.bitkit.ui.screens.wallets.receive.ReceiveSheet import to.bitkit.ui.screens.wallets.suggestion.BuyIntroScreen import to.bitkit.ui.screens.widgets.AddWidgetsScreen +import to.bitkit.ui.screens.widgets.suggestions.SuggestionsPreviewScreen import to.bitkit.ui.screens.widgets.WidgetsIntroScreen import to.bitkit.ui.screens.widgets.blocks.BlocksEditScreen import to.bitkit.ui.screens.widgets.blocks.BlocksPreviewScreen @@ -1395,8 +1396,15 @@ private fun NavGraphBuilder.widgets( WidgetType.WEATHER -> navController.navigate(Routes.WeatherPreview) } }, + onSuggestionsClick = { navController.navigate(Routes.SuggestionsPreview) }, fiatSymbol = LocalCurrencies.current.currencySymbol, - onBackCLick = { navController.popBackStack() } + onBackCLick = { navController.popBackStack() }, + ) + } + composableWithDefaultTransitions { + SuggestionsPreviewScreen( + onBackClick = { navController.popBackStack() }, + onAddWidget = { navController.navigateToHome() }, ) } composableWithDefaultTransitions { @@ -1981,6 +1989,9 @@ sealed interface Routes { @Serializable data object AddWidget : Routes + @Serializable + data object SuggestionsPreview : Routes + @Serializable data object Headlines : Routes diff --git a/app/src/main/java/to/bitkit/ui/screens/shop/shopDiscover/ShopDiscoverScreen.kt b/app/src/main/java/to/bitkit/ui/screens/shop/shopDiscover/ShopDiscoverScreen.kt index 8517a76eb..c20f204c3 100644 --- a/app/src/main/java/to/bitkit/ui/screens/shop/shopDiscover/ShopDiscoverScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/shop/shopDiscover/ShopDiscoverScreen.kt @@ -55,7 +55,7 @@ import to.bitkit.ui.theme.AppThemeSurface import to.bitkit.ui.theme.Colors import to.bitkit.ui.theme.Shapes -private const val SHOP_CARD_SIZE = 164 + @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -128,7 +128,7 @@ private fun ShopTabContent( description = stringResource(R.string.other__shop__discover__gift_cards__description), icon = R.drawable.gift, captionColor = Colors.Gray1, - size = SHOP_CARD_SIZE, + disableGlow = true, onClick = { navigateWebView("gift-cards", title) @@ -142,7 +142,7 @@ private fun ShopTabContent( description = stringResource(R.string.other__shop__discover__esims__description), icon = R.drawable.globe, captionColor = Colors.Gray1, - size = SHOP_CARD_SIZE, + disableGlow = true, onClick = { navigateWebView("esims", title2) @@ -163,7 +163,7 @@ private fun ShopTabContent( description = stringResource(R.string.other__shop__discover__refill__description), icon = R.drawable.phone, captionColor = Colors.Gray1, - size = SHOP_CARD_SIZE, + disableGlow = true, onClick = { navigateWebView("refill", title) @@ -176,7 +176,7 @@ private fun ShopTabContent( title = title2, description = stringResource(R.string.other__shop__discover__travel__description), icon = R.drawable.rocket_2, - size = SHOP_CARD_SIZE, + disableGlow = true, captionColor = Colors.Gray1, onClick = { diff --git a/app/src/main/java/to/bitkit/ui/screens/widgets/suggestions/SuggestionsPreviewScreen.kt b/app/src/main/java/to/bitkit/ui/screens/widgets/suggestions/SuggestionsPreviewScreen.kt new file mode 100644 index 000000000..81da70703 --- /dev/null +++ b/app/src/main/java/to/bitkit/ui/screens/widgets/suggestions/SuggestionsPreviewScreen.kt @@ -0,0 +1,146 @@ +package to.bitkit.ui.screens.widgets.suggestions + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.foundation.lazy.grid.items +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import to.bitkit.R +import to.bitkit.models.Suggestion +import to.bitkit.ui.components.BodyM +import to.bitkit.ui.components.FillHeight +import to.bitkit.ui.components.Headline +import to.bitkit.ui.components.PrimaryButton +import to.bitkit.ui.components.SuggestionCard +import to.bitkit.ui.components.Text13Up +import to.bitkit.ui.components.VerticalSpacer +import to.bitkit.ui.scaffold.AppTopBar +import to.bitkit.ui.scaffold.DrawerNavIcon +import to.bitkit.ui.scaffold.ScreenColumn +import to.bitkit.ui.theme.AppThemeSurface +import to.bitkit.ui.theme.Colors + +private val previewSuggestions = listOf(Suggestion.BUY, Suggestion.BACK_UP) + +@Composable +fun SuggestionsPreviewScreen( + onBackClick: () -> Unit, + onAddWidget: () -> Unit, +) { + Content( + onBackClick = onBackClick, + onAddWidget = onAddWidget, + ) +} + +@Composable +private fun Content( + onBackClick: () -> Unit, + onAddWidget: () -> Unit, +) { + ScreenColumn { + AppTopBar( + titleText = stringResource(R.string.widgets__widget__nav_title), + onBackClick = onBackClick, + actions = { DrawerNavIcon() }, + ) + + Column( + modifier = Modifier.padding(horizontal = 16.dp) + ) { + VerticalSpacer(26.dp) + + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween + ) { + Headline( + text = AnnotatedString(stringResource(R.string.widgets__suggestions__name)), + modifier = Modifier.width(200.dp) + ) + Icon( + painter = painterResource(R.drawable.widget_suggestions), + contentDescription = null, + tint = Color.Unspecified, + modifier = Modifier.size(64.dp) + ) + } + + BodyM( + text = stringResource(R.string.widgets__suggestions__description), + color = Colors.White64, + modifier = Modifier.padding(vertical = 16.dp) + ) + + HorizontalDivider() + + FillHeight() + + Text13Up( + stringResource(R.string.common__preview), + color = Colors.White64, + modifier = Modifier.padding(vertical = 16.dp) + ) + + LazyVerticalGrid( + columns = GridCells.Fixed(2), + horizontalArrangement = Arrangement.spacedBy(16.dp), + verticalArrangement = Arrangement.spacedBy(16.dp), + userScrollEnabled = false, + modifier = Modifier.fillMaxWidth() + ) { + items( + items = previewSuggestions, + key = { it.name } + ) { item -> + SuggestionCard( + gradientColor = item.color, + title = stringResource(item.title), + description = stringResource(item.description), + icon = item.icon, + disableGlow = true, + onClick = {}, + ) + } + } + + VerticalSpacer(21.dp) + + PrimaryButton( + text = stringResource(R.string.widgets__add), + onClick = onAddWidget, + modifier = Modifier.fillMaxWidth() + ) + + VerticalSpacer(21.dp) + } + } +} + +@Preview(showBackground = true) +@Composable +private fun Preview() { + AppThemeSurface { + Content( + onBackClick = {}, + onAddWidget = {}, + ) + } +} diff --git a/app/src/main/res/drawable/widget_suggestions.xml b/app/src/main/res/drawable/widget_suggestions.xml new file mode 100644 index 000000000..2fa730d04 --- /dev/null +++ b/app/src/main/res/drawable/widget_suggestions.xml @@ -0,0 +1,20 @@ + + + + + + From f59d13c45d64f93504093894985c2be146d9d28e Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Wed, 18 Feb 2026 14:15:18 -0300 Subject: [PATCH 11/32] chore: lint --- .../bitkit/ui/screens/shop/shopDiscover/ShopDiscoverScreen.kt | 2 -- app/src/main/java/to/bitkit/ui/screens/wallets/HomeViewModel.kt | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/app/src/main/java/to/bitkit/ui/screens/shop/shopDiscover/ShopDiscoverScreen.kt b/app/src/main/java/to/bitkit/ui/screens/shop/shopDiscover/ShopDiscoverScreen.kt index c20f204c3..b9fc346c8 100644 --- a/app/src/main/java/to/bitkit/ui/screens/shop/shopDiscover/ShopDiscoverScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/shop/shopDiscover/ShopDiscoverScreen.kt @@ -55,8 +55,6 @@ import to.bitkit.ui.theme.AppThemeSurface import to.bitkit.ui.theme.Colors import to.bitkit.ui.theme.Shapes - - @OptIn(ExperimentalMaterial3Api::class) @Composable fun ShopDiscoverScreen( diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeViewModel.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeViewModel.kt index 5302c2b40..3f9471af1 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeViewModel.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeViewModel.kt @@ -27,6 +27,7 @@ import to.bitkit.ui.screens.widgets.blocks.toWeatherModel import javax.inject.Inject import kotlin.time.Duration.Companion.seconds +@Suppress("TooManyFunctions") @HiltViewModel class HomeViewModel @Inject constructor( private val walletRepo: WalletRepo, @@ -295,7 +296,6 @@ class HomeViewModel @Inject constructor( } companion object { - private const val TAG = "HomeViewModel" private const val MAX_SUGGESTIONS = 4 } } From 634af1d06a67ce5efe65687aa87358cc8d854485 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Thu, 19 Feb 2026 14:19:20 -0300 Subject: [PATCH 12/32] feat: replace autogenerated icons --- .../bitkit/ui/screens/wallets/HomeScreen.kt | 3 +- .../ui/screens/widgets/AddWidgetsScreen.kt | 18 +++++------ app/src/main/res/drawable/ic_swipe_hint.xml | 9 ------ .../main/res/drawable/swipe_instruction.xml | 31 +++++++++++++++++++ .../main/res/drawable/widget_suggestions.xml | 14 +++++---- 5 files changed, 50 insertions(+), 25 deletions(-) delete mode 100644 app/src/main/res/drawable/ic_swipe_hint.xml create mode 100644 app/src/main/res/drawable/swipe_instruction.xml diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt index e3688a12f..1243e0136 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt @@ -452,6 +452,7 @@ private fun WalletPage( when (banner) { ActivityBannerType.SPENDING -> rootNavController.navigate(Routes.SettingUp) + ActivityBannerType.SAVINGS -> Unit } }, @@ -625,7 +626,7 @@ private fun WidgetsOnboardingHint(modifier: Modifier = Modifier) { ) HorizontalSpacer(16.dp) Icon( - painter = painterResource(R.drawable.ic_swipe_hint), + painter = painterResource(R.drawable.swipe_instruction), contentDescription = null, tint = Colors.White64, modifier = Modifier.size(40.dp) diff --git a/app/src/main/java/to/bitkit/ui/screens/widgets/AddWidgetsScreen.kt b/app/src/main/java/to/bitkit/ui/screens/widgets/AddWidgetsScreen.kt index e8fb45242..39280fde6 100644 --- a/app/src/main/java/to/bitkit/ui/screens/widgets/AddWidgetsScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/widgets/AddWidgetsScreen.kt @@ -33,15 +33,6 @@ fun AddWidgetsScreen( Column( modifier = Modifier.padding(horizontal = 16.dp) ) { - SettingsButtonRow( - title = stringResource(R.string.widgets__suggestions__name), - subtitle = stringResource(R.string.widgets__suggestions__description), - iconRes = R.drawable.widget_suggestions, - iconSize = 48.dp, - maxLinesSubtitle = 1, - onClick = onSuggestionsClick, - modifier = Modifier.testTag("WidgetListItem-suggestions") - ) SettingsButtonRow( title = stringResource(R.string.widgets__price__name), subtitle = stringResource(R.string.widgets__price__description), @@ -100,6 +91,15 @@ fun AddWidgetsScreen( onClick = { onWidgetSelected(WidgetType.CALCULATOR) }, modifier = Modifier.testTag("WidgetListItem-calculator") ) + SettingsButtonRow( + title = stringResource(R.string.widgets__suggestions__name), + subtitle = stringResource(R.string.widgets__suggestions__description), + iconRes = R.drawable.widget_suggestions, + iconSize = 48.dp, + maxLinesSubtitle = 1, + onClick = onSuggestionsClick, + modifier = Modifier.testTag("WidgetListItem-suggestions") + ) } } } diff --git a/app/src/main/res/drawable/ic_swipe_hint.xml b/app/src/main/res/drawable/ic_swipe_hint.xml deleted file mode 100644 index 5e60113a9..000000000 --- a/app/src/main/res/drawable/ic_swipe_hint.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/swipe_instruction.xml b/app/src/main/res/drawable/swipe_instruction.xml new file mode 100644 index 000000000..6ec67c2b2 --- /dev/null +++ b/app/src/main/res/drawable/swipe_instruction.xml @@ -0,0 +1,31 @@ + + + + + + + diff --git a/app/src/main/res/drawable/widget_suggestions.xml b/app/src/main/res/drawable/widget_suggestions.xml index 2fa730d04..f5ce0bbdd 100644 --- a/app/src/main/res/drawable/widget_suggestions.xml +++ b/app/src/main/res/drawable/widget_suggestions.xml @@ -7,14 +7,16 @@ android:pathData="M6.4,0L41.6,0A6.4,6.4 0,0 1,48 6.4L48,41.6A6.4,6.4 0,0 1,41.6 48L6.4,48A6.4,6.4 0,0 1,0 41.6L0,6.4A6.4,6.4 0,0 1,6.4 0z" android:fillColor="#FF4400"/> + android:pathData="M28.687,22.125V20.719C28.687,20.097 28.441,19.501 28.001,19.062C27.561,18.622 26.965,18.375 26.344,18.375C25.722,18.375 25.126,18.622 24.686,19.062C24.247,19.501 24,20.097 24,20.719V13.219C24,12.597 23.753,12.001 23.313,11.561C22.874,11.122 22.278,10.875 21.656,10.875C21.035,10.875 20.438,11.122 19.999,11.561C19.559,12.001 19.312,12.597 19.312,13.219V27.43L16.743,22.979C16.589,22.712 16.384,22.478 16.14,22.291C15.896,22.103 15.617,21.965 15.32,21.885C15.022,21.806 14.712,21.785 14.407,21.825C14.101,21.865 13.807,21.965 13.54,22.119C13.274,22.273 13.04,22.478 12.852,22.723C12.665,22.967 12.528,23.246 12.448,23.543C12.368,23.841 12.348,24.151 12.389,24.456C12.429,24.762 12.529,25.056 12.683,25.323C16.5,33.375 18.822,36.188 24,36.188C25.231,36.188 26.45,35.945 27.588,35.474C28.725,35.003 29.758,34.312 30.629,33.442C31.5,32.571 32.19,31.538 32.661,30.4C33.132,29.263 33.375,28.044 33.375,26.813V22.125C33.375,21.503 33.128,20.907 32.688,20.468C32.249,20.028 31.653,19.781 31.031,19.781C30.41,19.781 29.813,20.028 29.374,20.468C28.934,20.907 28.687,21.503 28.687,22.125V22.125Z" + android:strokeAlpha="0.2" + android:fillColor="#FF6600" + android:fillAlpha="0.2"/> + android:fillType="evenOdd"/> + android:fillType="evenOdd"/> From b134eb0a78ad41d23e71dcbd6fe7d9833dbac13b Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Thu, 19 Feb 2026 14:58:21 -0300 Subject: [PATCH 13/32] feat: make suggestions a widget type --- .../main/java/to/bitkit/models/WidgetType.kt | 4 + .../to/bitkit/repositories/WidgetsRepo.kt | 12 ++- app/src/main/java/to/bitkit/ui/ContentView.kt | 9 +- .../bitkit/ui/screens/wallets/HomeScreen.kt | 101 ++++++++++-------- .../ui/screens/widgets/AddWidgetsScreen.kt | 4 +- .../suggestions/SuggestionsPreviewScreen.kt | 79 +++++++++++--- .../suggestions/SuggestionsViewModel.kt | 44 ++++++++ 7 files changed, 179 insertions(+), 74 deletions(-) create mode 100644 app/src/main/java/to/bitkit/ui/screens/widgets/suggestions/SuggestionsViewModel.kt diff --git a/app/src/main/java/to/bitkit/models/WidgetType.kt b/app/src/main/java/to/bitkit/models/WidgetType.kt index 95d0c74bc..00f26bce4 100644 --- a/app/src/main/java/to/bitkit/models/WidgetType.kt +++ b/app/src/main/java/to/bitkit/models/WidgetType.kt @@ -31,5 +31,9 @@ enum class WidgetType( WEATHER( iconRes = R.drawable.widget_cloud, title = R.string.widgets__weather__name + ), + SUGGESTIONS( + iconRes = R.drawable.widget_suggestions, + title = R.string.widgets__suggestions__name, ) } diff --git a/app/src/main/java/to/bitkit/repositories/WidgetsRepo.kt b/app/src/main/java/to/bitkit/repositories/WidgetsRepo.kt index 66f7b2338..fb5746535 100644 --- a/app/src/main/java/to/bitkit/repositories/WidgetsRepo.kt +++ b/app/src/main/java/to/bitkit/repositories/WidgetsRepo.kt @@ -84,7 +84,7 @@ class WidgetsRepo @Inject constructor( private fun updateWidgetJobs(enabledWidgetTypes: Set) { val widgetTypesWithServices = WidgetType.entries.filter { - it != WidgetType.CALCULATOR + it != WidgetType.CALCULATOR && it != WidgetType.SUGGESTIONS } widgetTypesWithServices.forEach { widgetType -> @@ -138,7 +138,9 @@ class WidgetsRepo @Inject constructor( } } - WidgetType.CALCULATOR -> throw NotImplementedError("Calculator widget doesn't need a service") + WidgetType.CALCULATOR, + WidgetType.SUGGESTIONS, + -> throw NotImplementedError("Widget doesn't need a service") } widgetJobs[widgetType] = job @@ -226,8 +228,10 @@ class WidgetsRepo @Inject constructor( widgetsStore.updateBlock(block) } - WidgetType.CALCULATOR -> { - throw NotImplementedError("Calculator widget doesn't need a service") + WidgetType.CALCULATOR, + WidgetType.SUGGESTIONS, + -> { + throw NotImplementedError("Widget doesn't need a service") } WidgetType.FACTS -> updateWidget(factsService) { facts -> diff --git a/app/src/main/java/to/bitkit/ui/ContentView.kt b/app/src/main/java/to/bitkit/ui/ContentView.kt index de420783d..1c3f8c9dc 100644 --- a/app/src/main/java/to/bitkit/ui/ContentView.kt +++ b/app/src/main/java/to/bitkit/ui/ContentView.kt @@ -106,6 +106,7 @@ import to.bitkit.ui.screens.wallets.receive.ReceiveSheet import to.bitkit.ui.screens.wallets.suggestion.BuyIntroScreen import to.bitkit.ui.screens.widgets.AddWidgetsScreen import to.bitkit.ui.screens.widgets.suggestions.SuggestionsPreviewScreen +import to.bitkit.ui.screens.widgets.suggestions.SuggestionsViewModel import to.bitkit.ui.screens.widgets.WidgetsIntroScreen import to.bitkit.ui.screens.widgets.blocks.BlocksEditScreen import to.bitkit.ui.screens.widgets.blocks.BlocksPreviewScreen @@ -1394,17 +1395,19 @@ private fun NavGraphBuilder.widgets( WidgetType.NEWS -> navController.navigate(Routes.HeadlinesPreview) WidgetType.PRICE -> navController.navigate(Routes.PricePreview) WidgetType.WEATHER -> navController.navigate(Routes.WeatherPreview) + WidgetType.SUGGESTIONS -> navController.navigate(Routes.SuggestionsPreview) } }, - onSuggestionsClick = { navController.navigate(Routes.SuggestionsPreview) }, fiatSymbol = LocalCurrencies.current.currencySymbol, onBackCLick = { navController.popBackStack() }, ) } composableWithDefaultTransitions { + val viewModel = hiltViewModel() SuggestionsPreviewScreen( - onBackClick = { navController.popBackStack() }, - onAddWidget = { navController.navigateToHome() }, + suggestionsViewModel = viewModel, + onClose = { navController.navigateToHome() }, + onBack = { navController.popBackStack() }, ) } composableWithDefaultTransitions { diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt index 1243e0136..acb5bbb83 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt @@ -87,7 +87,6 @@ import to.bitkit.ui.components.StatusBarSpacer import to.bitkit.ui.components.SuggestionCard import to.bitkit.ui.components.TabBar import to.bitkit.ui.components.TertiaryButton -import to.bitkit.ui.components.Text13Up import to.bitkit.ui.components.TopBarSpacer import to.bitkit.ui.components.VerticalSpacer import to.bitkit.ui.components.WalletBalanceView @@ -257,6 +256,7 @@ fun HomeScreen( WidgetType.NEWS -> rootNavController.navigate(Routes.HeadlinesPreview) WidgetType.PRICE -> rootNavController.navigate(Routes.PricePreview) WidgetType.WEATHER -> rootNavController.navigate(Routes.WeatherPreview) + WidgetType.SUGGESTIONS -> rootNavController.navigate(Routes.SuggestionsPreview) } }, onClickDeleteWidget = { widgetType -> @@ -513,14 +513,6 @@ private fun WidgetsPage( TopBarSpacer() VerticalSpacer(16.dp) - AnimatedVisibility(homeUiState.suggestions.isNotEmpty()) { - SuggestionsSection( - suggestions = homeUiState.suggestions, - onRemoveSuggestion = onRemoveSuggestion, - onClickSuggestion = onClickSuggestion, - ) - } - if (homeUiState.isEditingWidgets) { DragDropColumn( items = homeUiState.widgetsWithPosition, @@ -540,7 +532,11 @@ private fun WidgetsPage( ) } } else { - Widgets(homeUiState) + Widgets( + homeUiState = homeUiState, + onRemoveSuggestion = onRemoveSuggestion, + onClickSuggestion = onClickSuggestion, + ) } VerticalSpacer(32.dp) @@ -571,42 +567,38 @@ private fun SuggestionsSection( ) { val rows = (suggestions.size + 1) / 2 - Column(modifier = modifier.padding(bottom = 32.dp)) { - Text13Up(stringResource(R.string.cards__suggestions), color = Colors.White64) - VerticalSpacer(16.dp) - BoxWithConstraints(modifier = Modifier.fillMaxWidth()) { - val cardSize = (maxWidth - 16.dp) / 2 - val gridHeight = (cardSize * rows) + (16.dp * (rows - 1)) - LazyVerticalGrid( - columns = GridCells.Fixed(2), - horizontalArrangement = Arrangement.spacedBy(16.dp), - verticalArrangement = Arrangement.spacedBy(16.dp), - userScrollEnabled = false, - modifier = Modifier - .fillMaxWidth() - .height(gridHeight) - .testTag("Suggestions") - ) { - items( - items = suggestions, - key = { it.name } - ) { item -> - SuggestionCard( - gradientColor = item.color, - title = stringResource(item.title), - description = stringResource(item.description), - icon = item.icon, - onClose = { onRemoveSuggestion(item) }.takeIf { item.dismissible }, - onClick = { onClickSuggestion(item) }, - modifier = Modifier - .testTag("Suggestion-${item.name.lowercase()}") - .animateItem( - fadeInSpec = tween(durationMillis = ANIMATION_DURATION_MS), - fadeOutSpec = tween(durationMillis = ANIMATION_DURATION_MS), - placementSpec = tween(durationMillis = ANIMATION_DURATION_MS), - ) - ) - } + BoxWithConstraints(modifier = modifier.fillMaxWidth()) { + val cardSize = (maxWidth - 16.dp) / 2 + val gridHeight = (cardSize * rows) + (16.dp * (rows - 1)) + LazyVerticalGrid( + columns = GridCells.Fixed(2), + horizontalArrangement = Arrangement.spacedBy(16.dp), + verticalArrangement = Arrangement.spacedBy(16.dp), + userScrollEnabled = false, + modifier = Modifier + .fillMaxWidth() + .height(gridHeight) + .testTag("Suggestions") + ) { + items( + items = suggestions, + key = { it.name } + ) { item -> + SuggestionCard( + gradientColor = item.color, + title = stringResource(item.title), + description = stringResource(item.description), + icon = item.icon, + onClose = { onRemoveSuggestion(item) }.takeIf { item.dismissible }, + onClick = { onClickSuggestion(item) }, + modifier = Modifier + .testTag("Suggestion-${item.name.lowercase()}") + .animateItem( + fadeInSpec = tween(durationMillis = ANIMATION_DURATION_MS), + fadeOutSpec = tween(durationMillis = ANIMATION_DURATION_MS), + placementSpec = tween(durationMillis = ANIMATION_DURATION_MS), + ) + ) } } } @@ -634,8 +626,13 @@ private fun WidgetsOnboardingHint(modifier: Modifier = Modifier) { } } +@Suppress("CyclomaticComplexMethod") @Composable -private fun Widgets(homeUiState: HomeUiState) { +private fun Widgets( + homeUiState: HomeUiState, + onRemoveSuggestion: (Suggestion) -> Unit, + onClickSuggestion: (Suggestion) -> Unit, +) { Column( modifier = Modifier.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(16.dp) @@ -726,6 +723,16 @@ private fun Widgets(homeUiState: HomeUiState) { ) } } + + WidgetType.SUGGESTIONS -> { + if (homeUiState.suggestions.isNotEmpty()) { + SuggestionsSection( + suggestions = homeUiState.suggestions, + onRemoveSuggestion = onRemoveSuggestion, + onClickSuggestion = onClickSuggestion, + ) + } + } } } } diff --git a/app/src/main/java/to/bitkit/ui/screens/widgets/AddWidgetsScreen.kt b/app/src/main/java/to/bitkit/ui/screens/widgets/AddWidgetsScreen.kt index 39280fde6..4c37a8008 100644 --- a/app/src/main/java/to/bitkit/ui/screens/widgets/AddWidgetsScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/widgets/AddWidgetsScreen.kt @@ -19,7 +19,6 @@ import to.bitkit.ui.theme.AppThemeSurface @Composable fun AddWidgetsScreen( onWidgetSelected: (WidgetType) -> Unit, - onSuggestionsClick: () -> Unit, onBackCLick: () -> Unit, fiatSymbol: String, ) { @@ -97,7 +96,7 @@ fun AddWidgetsScreen( iconRes = R.drawable.widget_suggestions, iconSize = 48.dp, maxLinesSubtitle = 1, - onClick = onSuggestionsClick, + onClick = { onWidgetSelected(WidgetType.SUGGESTIONS) }, modifier = Modifier.testTag("WidgetListItem-suggestions") ) } @@ -110,7 +109,6 @@ private fun Preview() { AppThemeSurface { AddWidgetsScreen( onWidgetSelected = {}, - onSuggestionsClick = {}, fiatSymbol = "$", onBackCLick = {}, ) diff --git a/app/src/main/java/to/bitkit/ui/screens/widgets/suggestions/SuggestionsPreviewScreen.kt b/app/src/main/java/to/bitkit/ui/screens/widgets/suggestions/SuggestionsPreviewScreen.kt index 81da70703..3c9e73d76 100644 --- a/app/src/main/java/to/bitkit/ui/screens/widgets/suggestions/SuggestionsPreviewScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/widgets/suggestions/SuggestionsPreviewScreen.kt @@ -13,6 +13,7 @@ import androidx.compose.foundation.lazy.grid.items import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -21,12 +22,14 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle import to.bitkit.R import to.bitkit.models.Suggestion import to.bitkit.ui.components.BodyM import to.bitkit.ui.components.FillHeight import to.bitkit.ui.components.Headline import to.bitkit.ui.components.PrimaryButton +import to.bitkit.ui.components.SecondaryButton import to.bitkit.ui.components.SuggestionCard import to.bitkit.ui.components.Text13Up import to.bitkit.ui.components.VerticalSpacer @@ -40,24 +43,38 @@ private val previewSuggestions = listOf(Suggestion.BUY, Suggestion.BACK_UP) @Composable fun SuggestionsPreviewScreen( - onBackClick: () -> Unit, - onAddWidget: () -> Unit, + suggestionsViewModel: SuggestionsViewModel, + onClose: () -> Unit, + onBack: () -> Unit, ) { + val isSuggestionsWidgetEnabled by suggestionsViewModel.isSuggestionsWidgetEnabled + .collectAsStateWithLifecycle() + Content( - onBackClick = onBackClick, - onAddWidget = onAddWidget, + onBack = onBack, + isSuggestionsWidgetEnabled = isSuggestionsWidgetEnabled, + onClickDelete = { + suggestionsViewModel.removeWidget() + onClose() + }, + onClickSave = { + suggestionsViewModel.addWidget() + onClose() + }, ) } @Composable private fun Content( - onBackClick: () -> Unit, - onAddWidget: () -> Unit, + onBack: () -> Unit, + isSuggestionsWidgetEnabled: Boolean, + onClickDelete: () -> Unit, + onClickSave: () -> Unit, ) { ScreenColumn { AppTopBar( titleText = stringResource(R.string.widgets__widget__nav_title), - onBackClick = onBackClick, + onBackClick = onBack, actions = { DrawerNavIcon() }, ) @@ -121,15 +138,28 @@ private fun Content( } } - VerticalSpacer(21.dp) - - PrimaryButton( - text = stringResource(R.string.widgets__add), - onClick = onAddWidget, - modifier = Modifier.fillMaxWidth() - ) + Row( + modifier = Modifier + .padding(vertical = 21.dp) + .fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(16.dp) + ) { + if (isSuggestionsWidgetEnabled) { + SecondaryButton( + text = stringResource(R.string.common__delete), + fullWidth = false, + onClick = onClickDelete, + modifier = Modifier.weight(1f), + ) + } - VerticalSpacer(21.dp) + PrimaryButton( + text = stringResource(R.string.common__save), + fullWidth = false, + onClick = onClickSave, + modifier = Modifier.weight(1f), + ) + } } } } @@ -139,8 +169,23 @@ private fun Content( private fun Preview() { AppThemeSurface { Content( - onBackClick = {}, - onAddWidget = {}, + onBack = {}, + isSuggestionsWidgetEnabled = false, + onClickDelete = {}, + onClickSave = {}, + ) + } +} + +@Preview(showBackground = true) +@Composable +private fun PreviewWithDelete() { + AppThemeSurface { + Content( + onBack = {}, + isSuggestionsWidgetEnabled = true, + onClickDelete = {}, + onClickSave = {}, ) } } diff --git a/app/src/main/java/to/bitkit/ui/screens/widgets/suggestions/SuggestionsViewModel.kt b/app/src/main/java/to/bitkit/ui/screens/widgets/suggestions/SuggestionsViewModel.kt new file mode 100644 index 000000000..afa8b5aa3 --- /dev/null +++ b/app/src/main/java/to/bitkit/ui/screens/widgets/suggestions/SuggestionsViewModel.kt @@ -0,0 +1,44 @@ +package to.bitkit.ui.screens.widgets.suggestions + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.launch +import to.bitkit.models.WidgetType +import to.bitkit.repositories.WidgetsRepo +import javax.inject.Inject + +@HiltViewModel +class SuggestionsViewModel @Inject constructor( + private val widgetsRepo: WidgetsRepo, +) : ViewModel() { + + companion object { + private const val SUBSCRIBE_TIMEOUT = 5000L + } + + val isSuggestionsWidgetEnabled: StateFlow = widgetsRepo.widgetsDataFlow + .map { widgetsData -> + widgetsData.widgets.any { it.type == WidgetType.SUGGESTIONS } + } + .stateIn(viewModelScope, SharingStarted.WhileSubscribed(SUBSCRIBE_TIMEOUT), false) + + val showWidgetTitles: StateFlow = widgetsRepo.showWidgetTitles + .stateIn(viewModelScope, SharingStarted.WhileSubscribed(SUBSCRIBE_TIMEOUT), false) + + fun addWidget() { + viewModelScope.launch { + widgetsRepo.addWidget(WidgetType.SUGGESTIONS) + } + } + + fun removeWidget() { + viewModelScope.launch { + widgetsRepo.deleteWidget(WidgetType.SUGGESTIONS) + } + } +} From eb3a667be409c856f8feabd8e75d55bdc1449189 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Mon, 23 Feb 2026 10:46:54 -0300 Subject: [PATCH 14/32] fix: check for pending transfer on showEmptyState --- .../to/bitkit/ui/screens/wallets/HomeViewModel.kt | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeViewModel.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeViewModel.kt index 3f9471af1..f28a3e764 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeViewModel.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeViewModel.kt @@ -83,10 +83,15 @@ class HomeViewModel @Inject constructor( viewModelScope.launch { combine( settingsStore.data, - walletRepo.balanceState - ) { settings, balanceState -> + walletRepo.balanceState, + transferRepo.activeTransfers, + ) { settings, balanceState, activeTransfers -> _uiState.value.copy( - showEmptyState = settings.showEmptyBalanceView && balanceState.totalSats == 0uL + showEmptyState = settings.showEmptyBalanceView && + balanceState.totalSats == 0uL && + balanceState.balanceInTransferToSpending == 0uL && + balanceState.balanceInTransferToSavings == 0uL && + activeTransfers.isEmpty() ) }.collect { newState -> _uiState.update { newState } From 63d4e38343d4e886124e960391354e0d81b05659 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Mon, 23 Feb 2026 11:09:12 -0300 Subject: [PATCH 15/32] fix: replace icon with image --- app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt index acb5bbb83..e875233ba 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt @@ -2,6 +2,7 @@ package to.bitkit.ui.screens.wallets import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.tween +import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -617,11 +618,9 @@ private fun WidgetsOnboardingHint(modifier: Modifier = Modifier) { modifier = Modifier.weight(1f) ) HorizontalSpacer(16.dp) - Icon( + Image( painter = painterResource(R.drawable.swipe_instruction), contentDescription = null, - tint = Colors.White64, - modifier = Modifier.size(40.dp) ) } } From bd60dbcb61bdb5635cc522d19efc6fab5da4c49f Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Mon, 23 Feb 2026 11:17:00 -0300 Subject: [PATCH 16/32] fix: implement Headline24 style --- .../main/java/to/bitkit/ui/components/Text.kt | 17 +++++++++++++++++ .../to/bitkit/ui/screens/wallets/HomeScreen.kt | 4 ++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/to/bitkit/ui/components/Text.kt b/app/src/main/java/to/bitkit/ui/components/Text.kt index 8bfa181b4..e30ad3b2d 100644 --- a/app/src/main/java/to/bitkit/ui/components/Text.kt +++ b/app/src/main/java/to/bitkit/ui/components/Text.kt @@ -84,6 +84,23 @@ fun Headline20( ) } +@Composable +fun Headline24( + text: AnnotatedString, + modifier: Modifier = Modifier, + color: Color = MaterialTheme.colorScheme.primary, +) { + Text( + text = text.toUpperCase(), + style = AppTextStyles.Headline.merge( + fontSize = 24.sp, + lineHeight = 24.sp, + color = color, + ), + modifier = modifier, + ) +} + @Composable fun Title( text: String, diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt index e875233ba..6788a3ad3 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt @@ -79,7 +79,7 @@ import to.bitkit.ui.Routes import to.bitkit.ui.components.ActivityBanner import to.bitkit.ui.components.AppStatus import to.bitkit.ui.components.BalanceHeaderView -import to.bitkit.ui.components.Display +import to.bitkit.ui.components.Headline24 import to.bitkit.ui.components.EmptyStateView import to.bitkit.ui.components.FillHeight import to.bitkit.ui.components.HorizontalSpacer @@ -613,7 +613,7 @@ private fun WidgetsOnboardingHint(modifier: Modifier = Modifier) { .fillMaxWidth() .padding(vertical = 32.dp) ) { - Display( + Headline24( text = stringResource(R.string.widgets__onboarding_swipe).withAccent(), modifier = Modifier.weight(1f) ) From 2d0ca86b014bb97c519b290fc0e5da8e905ebe24 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Mon, 23 Feb 2026 11:17:16 -0300 Subject: [PATCH 17/32] fix: accent tag --- app/src/main/res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5f4832314..85c401fe5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1000,7 +1000,7 @@ Widget Source Widgets - Swipe down\nto find your\nwidgets + Swipe down\nto find your\n<accent>widgets</accent> Discover everything Bitkit has to offer. Bitkit Suggestions From 10b1da18e0143a39c7540f140cfc027948cfcf17 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Mon, 23 Feb 2026 11:20:23 -0300 Subject: [PATCH 18/32] feat: image padding --- app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt index 6788a3ad3..f0b842754 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt @@ -621,6 +621,7 @@ private fun WidgetsOnboardingHint(modifier: Modifier = Modifier) { Image( painter = painterResource(R.drawable.swipe_instruction), contentDescription = null, + modifier = Modifier.padding(bottom = 12.dp) ) } } From 907df7dd4d9b38eeb24cf1ed39f4e73be7080308 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Mon, 23 Feb 2026 12:15:41 -0300 Subject: [PATCH 19/32] fix: bottom padding --- app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt index f0b842754..e6b14e118 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt @@ -97,6 +97,7 @@ import to.bitkit.ui.navigateToAllActivity import to.bitkit.ui.navigateToTransferFunding import to.bitkit.ui.navigateToTransferIntro import to.bitkit.ui.scaffold.AppAlertDialog +import to.bitkit.ui.theme.Insets import to.bitkit.ui.screens.wallets.activity.components.ActivityListSimple import to.bitkit.ui.screens.wallets.activity.utils.previewActivityItems import to.bitkit.ui.screens.widgets.DragAndDropWidget @@ -478,7 +479,7 @@ private fun WalletPage( } } - VerticalSpacer(150.dp) + VerticalSpacer(116.dp + Insets.Bottom) } } @@ -611,7 +612,7 @@ private fun WidgetsOnboardingHint(modifier: Modifier = Modifier) { verticalAlignment = Alignment.Bottom, modifier = modifier .fillMaxWidth() - .padding(vertical = 32.dp) + .padding(top = 32.dp) ) { Headline24( text = stringResource(R.string.widgets__onboarding_swipe).withAccent(), From ce97fccd7effabef090742a6c6db7f3c9c2851a7 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Mon, 23 Feb 2026 13:36:38 -0300 Subject: [PATCH 20/32] fix: cards alignment --- app/src/main/java/to/bitkit/ui/components/SuggestionCard.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/to/bitkit/ui/components/SuggestionCard.kt b/app/src/main/java/to/bitkit/ui/components/SuggestionCard.kt index cf1dd72c1..99b1862a5 100644 --- a/app/src/main/java/to/bitkit/ui/components/SuggestionCard.kt +++ b/app/src/main/java/to/bitkit/ui/components/SuggestionCard.kt @@ -26,6 +26,7 @@ import androidx.compose.material3.IconButton import androidx.compose.material3.ShapeDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Brush @@ -122,6 +123,7 @@ fun SuggestionCard( Image( painter = painterResource(icon), contentDescription = null, + alignment = Alignment.CenterStart, contentScale = ContentScale.FillHeight, modifier = Modifier.weight(1f) ) From e91c097592fb94b20603a1e2b7b74e7991dc976e Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Mon, 23 Feb 2026 13:41:20 -0300 Subject: [PATCH 21/32] fix: close suggestion icon color --- app/src/main/java/to/bitkit/ui/components/SuggestionCard.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/to/bitkit/ui/components/SuggestionCard.kt b/app/src/main/java/to/bitkit/ui/components/SuggestionCard.kt index 99b1862a5..aa16f51ad 100644 --- a/app/src/main/java/to/bitkit/ui/components/SuggestionCard.kt +++ b/app/src/main/java/to/bitkit/ui/components/SuggestionCard.kt @@ -138,7 +138,7 @@ fun SuggestionCard( Icon( painter = painterResource(R.drawable.ic_x), contentDescription = null, - tint = Colors.White, + tint = Colors.White64, ) } } From 169df7baff23a83275ff786e1683ee697fb788b7 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Mon, 23 Feb 2026 13:46:32 -0300 Subject: [PATCH 22/32] fix: show all padding --- .../ui/screens/wallets/activity/components/ActivityListSimple.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/activity/components/ActivityListSimple.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/activity/components/ActivityListSimple.kt index a8aa4f75f..bb5c9d4ab 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/activity/components/ActivityListSimple.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/activity/components/ActivityListSimple.kt @@ -38,7 +38,6 @@ fun ActivityListSimple( onClick = onAllActivityClick, modifier = Modifier .wrapContentWidth() - .padding(top = 8.dp) .testTag("ActivityShowAll") ) } From 767d5cd858540a64e0701b381b0e0fa25f7a6407 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Mon, 23 Feb 2026 13:52:41 -0300 Subject: [PATCH 23/32] fix: update show all label --- app/src/main/res/values-ar/strings.xml | 2 +- app/src/main/res/values-b+es+419/strings.xml | 2 +- app/src/main/res/values-ca/strings.xml | 2 +- app/src/main/res/values-cs/strings.xml | 2 +- app/src/main/res/values-de/strings.xml | 2 +- app/src/main/res/values-el/strings.xml | 2 +- app/src/main/res/values-es-rES/strings.xml | 2 +- app/src/main/res/values-es/strings.xml | 2 +- app/src/main/res/values-fr/strings.xml | 2 +- app/src/main/res/values-it/strings.xml | 2 +- app/src/main/res/values-nl/strings.xml | 2 +- app/src/main/res/values-pl/strings.xml | 2 +- app/src/main/res/values-pt-rBR/strings.xml | 2 +- app/src/main/res/values-pt/strings.xml | 2 +- app/src/main/res/values-ru/strings.xml | 2 +- app/src/main/res/values/strings.xml | 2 +- 16 files changed, 16 insertions(+), 16 deletions(-) diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 7bad49966..1ce6686ad 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -796,7 +796,7 @@ أُزيل من Mempool مُرسل أُرسل لنفسي - عرض كل النشاط + عرض الكل الحالة ناجح الكل diff --git a/app/src/main/res/values-b+es+419/strings.xml b/app/src/main/res/values-b+es+419/strings.xml index 16dcbef26..a619d6363 100644 --- a/app/src/main/res/values-b+es+419/strings.xml +++ b/app/src/main/res/values-b+es+419/strings.xml @@ -796,7 +796,7 @@ Eliminado de Mempool Enviado Enviado a mí mismo - Mostrar toda la actividad + Mostrar todo Estatus Éxito Todas diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index cb5e4ad8c..79d34ae77 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -796,7 +796,7 @@ Eliminat de la Mempool Enviat Enviat a mi mateix - Mostra tota l\'activitat + Mostra-ho tot Estat Exitós Tots diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 7182c5530..48fc95e61 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -796,7 +796,7 @@ Odebráno z Mempoolu Posláno Posláno sobě - Zobrazit veškerou aktivitu + Zobrazit vše Status Úspěch Vše diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 15d9fa57e..949139b26 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -866,7 +866,7 @@ Du wirst empfangen MINIMUM Aktivität - Alle Aktivitäten anzeigen + Alle anzeigen Noch keine Aktivitäten Empfange einige Gelder, um zu starten Gesendet diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index f5f597595..d5cde34c4 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -796,7 +796,7 @@ Αφαιρέθηκε από το Mempool Στάλθηκε Στάλθηκε στον εαυτό μου - Εμφάνιση όλης της δραστηριότητας + Εμφάνιση όλων Κατάσταση Επιτυχής Όλα diff --git a/app/src/main/res/values-es-rES/strings.xml b/app/src/main/res/values-es-rES/strings.xml index 531548579..243569e5d 100644 --- a/app/src/main/res/values-es-rES/strings.xml +++ b/app/src/main/res/values-es-rES/strings.xml @@ -796,7 +796,7 @@ Eliminado De Mempool Enviado Enviado a mí mismo - Mostrar toda la actividad + Mostrar todo Estatus Éxito Todas diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index e83746275..5d6ad056e 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -861,7 +861,7 @@ Recibirás MÍNIMO Actividad - Mostrar toda la actividad + Mostrar todo Aún no hay actividad Reciba algunos fondos para empezar Enviado diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index e225932ff..6f8a88b7c 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -856,7 +856,7 @@ Vous recevrez MINIMUM Activité - Afficher toutes les activités + Tout afficher Pas encore d\'activité Recevoir des fonds pour démarrer Envoyé diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 4820186a7..fe1348e62 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -796,7 +796,7 @@ Rimossa dalla Mempool Inviato Inviato a me stesso - Visualizza tutte le attività + Mostra tutto Stato Successo Tutti diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index d013e28af..2ce90640d 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -796,7 +796,7 @@ Verwijderd uit mempool Verzonden Naar mezelf verzonden - Alle activiteit tonen + Alles tonen Status Succesvol Alles diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 5e471c82d..9a2d808e1 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -856,7 +856,7 @@ Otrzymasz MINIMUM Aktywność - Pokaż całą aktywność + Pokaż wszystko Nie ma jeszcze aktywności Otrzymaj trochę środków aby rozpocząć Wysłane diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 81514d997..304fd5e94 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -796,7 +796,7 @@ Removido da Mempool Enviado Enviado para mim mesmo - Mostrar Todas as Atividades + Mostrar Tudo Status Sucesso Todos diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 3183fda3e..f20ecd545 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -811,7 +811,7 @@ Você receberá MÍNIMO Atividade - Mostrar Todas as Atividades + Mostrar Tudo Nenhuma atividade ainda Receba alguns bitcoins para começar Enviado diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index cac54ff2f..2bfc91051 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -813,7 +813,7 @@ Удалено из мемпула Отправлено Отправлено себе - Показать Все + Показать все Статус Успешно Все diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 85c401fe5..00f732672 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -798,7 +798,7 @@ Removed from Mempool Sent Sent to myself - Show All Activity + Show All Status Successful All From 9dc135ca3d2bb71276187ba91bb0ce7e7e1ee5be Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Mon, 23 Feb 2026 14:10:43 -0300 Subject: [PATCH 24/32] fix: TabBar height --- app/src/main/java/to/bitkit/ui/components/TabBar.kt | 6 ++++-- .../main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/to/bitkit/ui/components/TabBar.kt b/app/src/main/java/to/bitkit/ui/components/TabBar.kt index fd629f34e..3914a72b6 100644 --- a/app/src/main/java/to/bitkit/ui/components/TabBar.kt +++ b/app/src/main/java/to/bitkit/ui/components/TabBar.kt @@ -50,6 +50,8 @@ import to.bitkit.ui.theme.Colors private val iconToTextGap = 4.dp private val iconSize = 20.dp +const val TAB_BAR_HEIGHT = 56 + private val buttonLeftShape = RoundedCornerShape(topStartPercent = 50, bottomStartPercent = 50) private val buttonRightShape = RoundedCornerShape(topEndPercent = 50, bottomEndPercent = 50) @@ -81,7 +83,7 @@ fun BoxScope.TabBar( contentAlignment = Alignment.Center, modifier = Modifier .weight(1f) - .height(60.dp) + .height(TAB_BAR_HEIGHT.dp) .clip(buttonLeftShape) .clickable { onSendClick() } .testTag("Send") @@ -102,7 +104,7 @@ fun BoxScope.TabBar( contentAlignment = Alignment.Center, modifier = Modifier .weight(1f) - .height(60.dp) + .height(TAB_BAR_HEIGHT.dp) .clip(buttonRightShape) .clickable { onReceiveClick() } .testTag("Receive") diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt index e6b14e118..ef8a1e6c5 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt @@ -86,6 +86,7 @@ import to.bitkit.ui.components.HorizontalSpacer import to.bitkit.ui.components.Sheet import to.bitkit.ui.components.StatusBarSpacer import to.bitkit.ui.components.SuggestionCard +import to.bitkit.ui.components.TAB_BAR_HEIGHT import to.bitkit.ui.components.TabBar import to.bitkit.ui.components.TertiaryButton import to.bitkit.ui.components.TopBarSpacer @@ -479,7 +480,7 @@ private fun WalletPage( } } - VerticalSpacer(116.dp + Insets.Bottom) + VerticalSpacer(TAB_BAR_HEIGHT.dp + 56.dp + Insets.Bottom) } } From ad0ab3e9ef33dfdf465cc08c565399cf68fe15ca Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Mon, 23 Feb 2026 14:25:31 -0300 Subject: [PATCH 25/32] fix: TabBar bottom padding --- app/src/main/java/to/bitkit/ui/components/TabBar.kt | 3 ++- app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/to/bitkit/ui/components/TabBar.kt b/app/src/main/java/to/bitkit/ui/components/TabBar.kt index 3914a72b6..4a305e789 100644 --- a/app/src/main/java/to/bitkit/ui/components/TabBar.kt +++ b/app/src/main/java/to/bitkit/ui/components/TabBar.kt @@ -51,6 +51,7 @@ private val iconToTextGap = 4.dp private val iconSize = 20.dp const val TAB_BAR_HEIGHT = 56 +const val TAB_BAR_PADDING_BOTTOM = 8 private val buttonLeftShape = RoundedCornerShape(topStartPercent = 50, bottomStartPercent = 50) private val buttonRightShape = RoundedCornerShape(topEndPercent = 50, bottomEndPercent = 50) @@ -69,7 +70,7 @@ fun BoxScope.TabBar( .align(Alignment.BottomCenter) .fillMaxWidth() .padding(horizontal = 16.dp) - .padding(bottom = 16.dp) + .padding(bottom = TAB_BAR_PADDING_BOTTOM.dp) .navigationBarsPadding() ) { Row( diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt index ef8a1e6c5..1726cf649 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt @@ -87,6 +87,7 @@ import to.bitkit.ui.components.Sheet import to.bitkit.ui.components.StatusBarSpacer import to.bitkit.ui.components.SuggestionCard import to.bitkit.ui.components.TAB_BAR_HEIGHT +import to.bitkit.ui.components.TAB_BAR_PADDING_BOTTOM import to.bitkit.ui.components.TabBar import to.bitkit.ui.components.TertiaryButton import to.bitkit.ui.components.TopBarSpacer @@ -480,7 +481,7 @@ private fun WalletPage( } } - VerticalSpacer(TAB_BAR_HEIGHT.dp + 56.dp + Insets.Bottom) + VerticalSpacer(TAB_BAR_HEIGHT.dp + TAB_BAR_PADDING_BOTTOM.dp + 36.dp + Insets.Bottom) } } From 1d91ee074f39e3898e5e497b83dd4ed7150048c2 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Mon, 23 Feb 2026 14:33:07 -0300 Subject: [PATCH 26/32] fix: remove empty state bottom padding --- app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt index 1726cf649..bfb904e3c 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt @@ -490,7 +490,6 @@ private fun WalletPage( text = stringResource(R.string.onboarding__empty_wallet).withAccent(), modifier = Modifier .align(Alignment.BottomCenter) - .padding(bottom = 24.dp) ) } } From 37180db037ce113d8e1fb59de9a5cc808d324a41 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Mon, 23 Feb 2026 14:35:55 -0300 Subject: [PATCH 27/32] fix: support icon height --- app/src/main/java/to/bitkit/ui/components/SuggestionCard.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/to/bitkit/ui/components/SuggestionCard.kt b/app/src/main/java/to/bitkit/ui/components/SuggestionCard.kt index aa16f51ad..46a7bfe96 100644 --- a/app/src/main/java/to/bitkit/ui/components/SuggestionCard.kt +++ b/app/src/main/java/to/bitkit/ui/components/SuggestionCard.kt @@ -14,6 +14,7 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.defaultMinSize import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding @@ -125,7 +126,9 @@ fun SuggestionCard( contentDescription = null, alignment = Alignment.CenterStart, contentScale = ContentScale.FillHeight, - modifier = Modifier.weight(1f) + modifier = Modifier + .defaultMinSize(minHeight = 96.dp) + .weight(1f) ) if (onClose != null) { From adf2779f48dc4f81950bb6f067a3fa55acb9801e Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Mon, 23 Feb 2026 14:41:31 -0300 Subject: [PATCH 28/32] feat: update default widgets set --- app/src/main/java/to/bitkit/data/WidgetsStore.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/to/bitkit/data/WidgetsStore.kt b/app/src/main/java/to/bitkit/data/WidgetsStore.kt index 13487b950..1f50c447c 100644 --- a/app/src/main/java/to/bitkit/data/WidgetsStore.kt +++ b/app/src/main/java/to/bitkit/data/WidgetsStore.kt @@ -160,9 +160,9 @@ class WidgetsStore @Inject constructor( @Serializable data class WidgetsData( val widgets: List = listOf( - WidgetWithPosition(type = WidgetType.PRICE, position = 0), - WidgetWithPosition(type = WidgetType.BLOCK, position = 1), - WidgetWithPosition(type = WidgetType.NEWS, position = 2), + WidgetWithPosition(type = WidgetType.SUGGESTIONS, position = 0), + WidgetWithPosition(type = WidgetType.PRICE, position = 1), + WidgetWithPosition(type = WidgetType.BLOCK, position = 2), ), val headlinePreferences: HeadlinePreferences = HeadlinePreferences(), val factsPreferences: FactsPreferences = FactsPreferences(), From 6b3b1440197f4620fc3fb97ce832cc0af0464f35 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Mon, 23 Feb 2026 14:51:29 -0300 Subject: [PATCH 29/32] feat: icon edit widget --- .../bitkit/ui/screens/wallets/HomeScreen.kt | 4 ++-- app/src/main/res/drawable/ic_edit.xml | 23 +++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 app/src/main/res/drawable/ic_edit.xml diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt index bfb904e3c..b118bb423 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt @@ -775,11 +775,11 @@ private fun TopBar( onClick = onClickEditWidgetList, modifier = Modifier.testTag("WidgetsEdit") ) { - Icon( + Image( painter = if (isEditingWidgets) { painterResource(R.drawable.ic_check) } else { - painterResource(R.drawable.ic_sort_ascending) + painterResource(R.drawable.ic_edit) }, contentDescription = null, ) diff --git a/app/src/main/res/drawable/ic_edit.xml b/app/src/main/res/drawable/ic_edit.xml new file mode 100644 index 000000000..bd9ebb0c4 --- /dev/null +++ b/app/src/main/res/drawable/ic_edit.xml @@ -0,0 +1,23 @@ + + + + + + From 37c4985e0646b07dd3aa6e344f69139732a3ba55 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Mon, 23 Feb 2026 14:52:15 -0300 Subject: [PATCH 30/32] fix: drawer icon color --- .../main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt index b118bb423..19891244c 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt @@ -16,7 +16,6 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.statusBars import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.LazyVerticalGrid @@ -79,9 +78,9 @@ import to.bitkit.ui.Routes import to.bitkit.ui.components.ActivityBanner import to.bitkit.ui.components.AppStatus import to.bitkit.ui.components.BalanceHeaderView -import to.bitkit.ui.components.Headline24 import to.bitkit.ui.components.EmptyStateView import to.bitkit.ui.components.FillHeight +import to.bitkit.ui.components.Headline24 import to.bitkit.ui.components.HorizontalSpacer import to.bitkit.ui.components.Sheet import to.bitkit.ui.components.StatusBarSpacer @@ -99,7 +98,6 @@ import to.bitkit.ui.navigateToAllActivity import to.bitkit.ui.navigateToTransferFunding import to.bitkit.ui.navigateToTransferIntro import to.bitkit.ui.scaffold.AppAlertDialog -import to.bitkit.ui.theme.Insets import to.bitkit.ui.screens.wallets.activity.components.ActivityListSimple import to.bitkit.ui.screens.wallets.activity.utils.previewActivityItems import to.bitkit.ui.screens.widgets.DragAndDropWidget @@ -116,6 +114,7 @@ import to.bitkit.ui.sheets.BackupRoute import to.bitkit.ui.sheets.PinRoute import to.bitkit.ui.theme.AppThemeSurface import to.bitkit.ui.theme.Colors +import to.bitkit.ui.theme.Insets import to.bitkit.ui.utils.withAccent import to.bitkit.viewmodels.ActivityListViewModel import to.bitkit.viewmodels.AppViewModel @@ -793,6 +792,7 @@ private fun TopBar( ) { Icon( painter = painterResource(R.drawable.ic_list), + tint = Colors.White, contentDescription = stringResource(R.string.settings__settings), ) } From bbed75983476d8f2ce78ab0539f8249d78f3ae97 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Mon, 23 Feb 2026 15:07:58 -0300 Subject: [PATCH 31/32] fix: remove unnecessary spacer --- .../main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt index 19891244c..0949a1f0e 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt @@ -769,7 +769,7 @@ private fun TopBar( TopAppBar( title = {}, actions = { - if (showEditWidgets) { + AnimatedVisibility(showEditWidgets) { IconButton( onClick = onClickEditWidgetList, modifier = Modifier.testTag("WidgetsEdit") @@ -784,8 +784,9 @@ private fun TopBar( ) } } - AppStatus(onClick = { rootNavController.navigate(Routes.AppStatus) }) - HorizontalSpacer(4.dp) + AppStatus( + onClick = { rootNavController.navigate(Routes.AppStatus) }, + ) IconButton( onClick = { scope.launch { drawerState.open() } }, modifier = Modifier.testTag("HeaderMenu") From 8a97b12051fc6687cc4fa256b9f8f46392f256d8 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Mon, 23 Feb 2026 15:14:43 -0300 Subject: [PATCH 32/32] fix: icon color --- app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt index 0949a1f0e..ebfb2e42c 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt @@ -774,12 +774,13 @@ private fun TopBar( onClick = onClickEditWidgetList, modifier = Modifier.testTag("WidgetsEdit") ) { - Image( + Icon( painter = if (isEditingWidgets) { painterResource(R.drawable.ic_check) } else { painterResource(R.drawable.ic_edit) }, + tint = Colors.White, contentDescription = null, ) }