From f061c774970a607c318ce4d41c3ea79df5df8ef8 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Mon, 25 May 2026 10:01:11 -0300 Subject: [PATCH 01/15] fix: add widgets icon --- .../main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt | 7 +++++++ 1 file changed, 7 insertions(+) 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 ef7625bf2..4c3f2e0f2 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 @@ -793,6 +793,13 @@ private fun WidgetsPage( text = stringResource(R.string.widgets__add), onClick = onClickAddWidget, enabled = !isCalculatorInputActive, + icon = { + Icon( + painter = painterResource(R.drawable.ic_plus), + contentDescription = null, + modifier = Modifier.size(16.dp) + ) + }, modifier = Modifier .alpha(footerAlpha) .testTag("WidgetsAdd") From 2ca84a7b0d9ac51500bd6fbc0a66c2d75e9ab57c Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Mon, 25 May 2026 10:06:51 -0300 Subject: [PATCH 02/15] fix: implement PinnedTabsScaffold with dropshadow effect --- .../ui/components/PinnedTabsScaffold.kt | 64 +++++++++++++++++++ .../shop/shopDiscover/ShopDiscoverScreen.kt | 36 +++++++---- .../wallets/activity/AllActivityScreen.kt | 49 ++++++-------- .../to/bitkit/ui/settings/SettingsScreen.kt | 60 ++++++++++------- changelog.d/next/916.changed.md | 1 + 5 files changed, 144 insertions(+), 66 deletions(-) create mode 100644 app/src/main/java/to/bitkit/ui/components/PinnedTabsScaffold.kt create mode 100644 changelog.d/next/916.changed.md diff --git a/app/src/main/java/to/bitkit/ui/components/PinnedTabsScaffold.kt b/app/src/main/java/to/bitkit/ui/components/PinnedTabsScaffold.kt new file mode 100644 index 000000000..31c3d8280 --- /dev/null +++ b/app/src/main/java/to/bitkit/ui/components/PinnedTabsScaffold.kt @@ -0,0 +1,64 @@ +package to.bitkit.ui.components + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.offset +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.onSizeChanged +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import androidx.compose.ui.zIndex +import to.bitkit.ui.theme.Colors + +private val PinnedTabsShadowHeight = 32.dp + +@Composable +fun PinnedTabsScaffold( + header: @Composable ColumnScope.() -> Unit, + modifier: Modifier = Modifier, + content: @Composable (topPadding: Dp) -> Unit, +) { + val density = LocalDensity.current + var headerHeight by remember { mutableStateOf(0.dp) } + val shadowBrush = remember { + Brush.verticalGradient(colors = listOf(Colors.Black, Color.Transparent)) + } + + Box(modifier = modifier.fillMaxSize()) { + content(headerHeight) + + Box( + modifier = Modifier + .fillMaxWidth() + .offset(y = headerHeight) + .height(PinnedTabsShadowHeight) + .background(shadowBrush) + .zIndex(1f) + ) + + Column( + modifier = Modifier + .align(Alignment.TopStart) + .fillMaxWidth() + .background(Colors.Black) + .zIndex(2f) + .onSizeChanged { headerHeight = with(density) { it.height.toDp() } } + ) { + header() + } + } +} 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 616ed7e7b..6ba386131 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 @@ -8,6 +8,7 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding @@ -37,6 +38,7 @@ import to.bitkit.env.Env import to.bitkit.ext.configureForBasicWebContent import to.bitkit.models.BitrefillCategory import to.bitkit.ui.components.BodyM +import to.bitkit.ui.components.PinnedTabsScaffold import to.bitkit.ui.components.SuggestionCard import to.bitkit.ui.components.Text13Up import to.bitkit.ui.components.VerticalSpacer @@ -73,17 +75,25 @@ fun ShopDiscoverScreen( actions = { DrawerNavIcon() }, ) - CustomTabRowWithSpacing( - tabs = tabs, - currentTabIndex = tabs.indexOf(selectedTab), - selectedColor = Colors.White, - onTabChange = { selectedTab = it }, - modifier = Modifier.padding(horizontal = 16.dp) - ) + PinnedTabsScaffold( + header = { + CustomTabRowWithSpacing( + tabs = tabs, + currentTabIndex = tabs.indexOf(selectedTab), + selectedColor = Colors.White, + onTabChange = { selectedTab = it }, + modifier = Modifier.padding(horizontal = 16.dp) + ) + } + ) { topPadding -> + when (selectedTab) { + ShopDiscoverTab.Shop -> ShopTabContent( + navigateWebView = navigateWebView, + contentPadding = PaddingValues(top = topPadding, bottom = 42.dp), + ) - when (selectedTab) { - ShopDiscoverTab.Shop -> ShopTabContent(navigateWebView = navigateWebView) - ShopDiscoverTab.Map -> MapTabContent() + ShopDiscoverTab.Map -> MapTabContent(modifier = Modifier.padding(top = topPadding)) + } } } } @@ -92,13 +102,13 @@ fun ShopDiscoverScreen( private fun ShopTabContent( navigateWebView: (String, String) -> Unit, modifier: Modifier = Modifier, + contentPadding: PaddingValues = PaddingValues(0.dp), ) { LazyColumn( + contentPadding = contentPadding, modifier = modifier.padding(horizontal = 16.dp) ) { item { - VerticalSpacer(16.dp) - Row( horizontalArrangement = Arrangement.spacedBy(16.dp), ) { @@ -229,7 +239,7 @@ private fun MapTabContent( Box( contentAlignment = Alignment.Center, modifier = modifier - .padding(top = 16.dp, start = 16.dp, end = 16.dp) + .padding(start = 16.dp, end = 16.dp) .clip(Shapes.medium) ) { AndroidView( diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/activity/AllActivityScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/activity/AllActivityScreen.kt index 079264f31..d0d98f84f 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/activity/AllActivityScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/activity/AllActivityScreen.kt @@ -1,11 +1,7 @@ package to.bitkit.ui.screens.wallets.activity -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.runtime.Composable @@ -17,7 +13,6 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.synonym.bitkitcore.Activity -import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableSet import kotlinx.collections.immutable.persistentListOf @@ -25,6 +20,7 @@ import kotlinx.collections.immutable.persistentSetOf import kotlinx.collections.immutable.toImmutableList import to.bitkit.R import to.bitkit.ui.appViewModel +import to.bitkit.ui.components.PinnedTabsScaffold import to.bitkit.ui.components.Sheet import to.bitkit.ui.scaffold.AppTopBar import to.bitkit.ui.scaffold.DrawerNavIcon @@ -75,7 +71,6 @@ fun AllActivityScreen( } @Composable -@OptIn(ExperimentalHazeMaterialsApi::class) private fun AllActivityScreenContent( filteredActivities: ImmutableList?, searchText: String, @@ -104,33 +99,29 @@ private fun AllActivityScreenContent( }, ) - ActivityListFilter( - searchText = searchText, - onSearchTextChange = onSearchTextChange, - hasTagFilter = hasTagFilter, - hasDateRangeFilter = hasDateRangeFilter, - onTagClick = onTagClick, - selectedTags = selectedTags, - onRemoveTag = onRemoveTag, - onDateRangeClick = onDateRangeClick, - tabs = tabs, - currentTabIndex = currentTabIndex, - onTabChange = { onTabChange(tabs.indexOf(it)) }, - modifier = Modifier.padding(horizontal = 16.dp) - - ) - Spacer(modifier = Modifier.height(16.dp)) - - // List - Box( - modifier = Modifier - .fillMaxSize() - ) { + PinnedTabsScaffold( + header = { + ActivityListFilter( + searchText = searchText, + onSearchTextChange = onSearchTextChange, + hasTagFilter = hasTagFilter, + hasDateRangeFilter = hasDateRangeFilter, + onTagClick = onTagClick, + selectedTags = selectedTags, + onRemoveTag = onRemoveTag, + onDateRangeClick = onDateRangeClick, + tabs = tabs, + currentTabIndex = currentTabIndex, + onTabChange = { onTabChange(tabs.indexOf(it)) }, + modifier = Modifier.padding(horizontal = 16.dp) + ) + } + ) { topPadding -> ActivityListGrouped( items = filteredActivities, onActivityItemClick = onActivityItemClick, onEmptyActivityRowClick = onEmptyActivityRowClick, - contentPadding = PaddingValues(top = 0.dp), + contentPadding = PaddingValues(top = topPadding), modifier = Modifier .swipeToChangeTab( currentTabIndex = currentTabIndex, diff --git a/app/src/main/java/to/bitkit/ui/settings/SettingsScreen.kt b/app/src/main/java/to/bitkit/ui/settings/SettingsScreen.kt index 329674c2a..03f56dbdf 100644 --- a/app/src/main/java/to/bitkit/ui/settings/SettingsScreen.kt +++ b/app/src/main/java/to/bitkit/ui/settings/SettingsScreen.kt @@ -19,6 +19,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle @@ -33,6 +34,7 @@ import to.bitkit.ui.LocalCurrencies import to.bitkit.ui.Routes import to.bitkit.ui.appViewModel import to.bitkit.ui.components.AuthCheckAction +import to.bitkit.ui.components.PinnedTabsScaffold import to.bitkit.ui.components.Sheet import to.bitkit.ui.components.VerticalSpacer import to.bitkit.ui.components.settings.SectionHeader @@ -220,30 +222,37 @@ private fun SettingsContent( actions = { DrawerNavIcon() }, ) - CustomTabRowWithSpacing( - tabs = tabs, - currentTabIndex = pagerState.currentPage, - selectedColor = Colors.White, - onTabChange = { scope.launch { pagerState.animateScrollToPage(tabs.indexOf(it)) } }, - modifier = Modifier.padding(horizontal = 16.dp) - ) - - HorizontalPager(state = pagerState) { page -> - when (tabs[page]) { - SettingsTab.General -> GeneralTabContent( - state = generalState, - onEvent = onEvent, + PinnedTabsScaffold( + header = { + CustomTabRowWithSpacing( + tabs = tabs, + currentTabIndex = pagerState.currentPage, + selectedColor = Colors.White, + onTabChange = { scope.launch { pagerState.animateScrollToPage(tabs.indexOf(it)) } }, + modifier = Modifier.padding(horizontal = 16.dp) ) + } + ) { topPadding -> + HorizontalPager(state = pagerState) { page -> + when (tabs[page]) { + SettingsTab.General -> GeneralTabContent( + state = generalState, + onEvent = onEvent, + topPadding = topPadding, + ) - SettingsTab.Security -> SecurityTabContent( - state = securityState, - onEvent = onEvent, - ) + SettingsTab.Security -> SecurityTabContent( + state = securityState, + onEvent = onEvent, + topPadding = topPadding, + ) - SettingsTab.Advanced -> AdvancedTabContent( - state = advancedState, - onEvent = onEvent, - ) + SettingsTab.Advanced -> AdvancedTabContent( + state = advancedState, + onEvent = onEvent, + topPadding = topPadding, + ) + } } } } @@ -253,12 +262,13 @@ private fun SettingsContent( private fun GeneralTabContent( state: GeneralTabState, onEvent: OnSettingsEvent, + topPadding: Dp = 0.dp, ) { Column( modifier = Modifier .fillMaxSize() - .padding(horizontal = 16.dp) .verticalScroll(rememberScrollState()) + .padding(top = topPadding, start = 16.dp, end = 16.dp) ) { SectionHeader(title = stringResource(R.string.settings__general__section_interface)) @@ -364,12 +374,13 @@ private fun GeneralTabContent( private fun SecurityTabContent( state: SecurityTabState, onEvent: OnSettingsEvent, + topPadding: Dp = 0.dp, ) { Column( modifier = Modifier .fillMaxSize() - .padding(horizontal = 16.dp) .verticalScroll(rememberScrollState()) + .padding(top = topPadding, start = 16.dp, end = 16.dp) ) { SectionHeader(title = stringResource(R.string.settings__security__section_backup)) @@ -480,12 +491,13 @@ private fun SecurityTabContent( private fun AdvancedTabContent( state: AdvancedTabState, onEvent: OnSettingsEvent, + topPadding: Dp = 0.dp, ) { Column( modifier = Modifier .fillMaxSize() - .padding(horizontal = 16.dp) .verticalScroll(rememberScrollState()) + .padding(top = topPadding, start = 16.dp, end = 16.dp) .testTag("advanced_settings_screen") ) { if (state.isDevModeEnabled) { diff --git a/changelog.d/next/916.changed.md b/changelog.d/next/916.changed.md new file mode 100644 index 000000000..b6e012af1 --- /dev/null +++ b/changelog.d/next/916.changed.md @@ -0,0 +1 @@ +Activity, Shop and Settings now keep their tabs pinned with a drop shadow as content scrolls behind them, the Add Widget button shows its icon, and the Shop list has more bottom spacing. From bfe3429011ad657254375529ef30a45195c9d558 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Mon, 25 May 2026 10:18:17 -0300 Subject: [PATCH 03/15] fix: implement viewpager --- .../shop/shopDiscover/ShopDiscoverScreen.kt | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 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 6ba386131..42935f5a5 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 @@ -15,6 +15,8 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.pager.HorizontalPager +import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.HorizontalDivider @@ -23,6 +25,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -33,6 +36,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView import kotlinx.collections.immutable.toImmutableList +import kotlinx.coroutines.launch import to.bitkit.R import to.bitkit.env.Env import to.bitkit.ext.configureForBasicWebContent @@ -66,7 +70,8 @@ fun ShopDiscoverScreen( modifier: Modifier = Modifier, ) { val tabs = remember { ShopDiscoverTab.entries.toImmutableList() } - var selectedTab by remember { mutableStateOf(ShopDiscoverTab.Shop) } + val pagerState = rememberPagerState(pageCount = { tabs.size }) + val scope = rememberCoroutineScope() ScreenColumn(modifier = modifier) { AppTopBar( @@ -79,20 +84,25 @@ fun ShopDiscoverScreen( header = { CustomTabRowWithSpacing( tabs = tabs, - currentTabIndex = tabs.indexOf(selectedTab), + currentTabIndex = pagerState.currentPage, selectedColor = Colors.White, - onTabChange = { selectedTab = it }, + onTabChange = { scope.launch { pagerState.animateScrollToPage(tabs.indexOf(it)) } }, modifier = Modifier.padding(horizontal = 16.dp) ) } ) { topPadding -> - when (selectedTab) { - ShopDiscoverTab.Shop -> ShopTabContent( - navigateWebView = navigateWebView, - contentPadding = PaddingValues(top = topPadding, bottom = 42.dp), - ) + HorizontalPager( + state = pagerState, + userScrollEnabled = tabs[pagerState.settledPage] != ShopDiscoverTab.Map, + ) { page -> + when (tabs[page]) { + ShopDiscoverTab.Shop -> ShopTabContent( + navigateWebView = navigateWebView, + contentPadding = PaddingValues(top = topPadding, bottom = 42.dp), + ) - ShopDiscoverTab.Map -> MapTabContent(modifier = Modifier.padding(top = topPadding)) + ShopDiscoverTab.Map -> MapTabContent(modifier = Modifier.padding(top = topPadding)) + } } } } From 6fb99d4f44ab40cb3f72b8498716cbd89a77ad12 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Mon, 25 May 2026 10:27:53 -0300 Subject: [PATCH 04/15] fix: map top padding --- .../bitkit/ui/screens/shop/shopDiscover/ShopDiscoverScreen.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 42935f5a5..503046b68 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 @@ -119,6 +119,8 @@ private fun ShopTabContent( modifier = modifier.padding(horizontal = 16.dp) ) { item { + VerticalSpacer(16.dp) + Row( horizontalArrangement = Arrangement.spacedBy(16.dp), ) { @@ -249,7 +251,7 @@ private fun MapTabContent( Box( contentAlignment = Alignment.Center, modifier = modifier - .padding(start = 16.dp, end = 16.dp) + .padding(start = 16.dp, end = 16.dp, top = 16.dp) .clip(Shapes.medium) ) { AndroidView( From 8358f89402e986fcf30b0edb8ebfce8a22733aec Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Mon, 25 May 2026 11:03:37 -0300 Subject: [PATCH 05/15] fix: implement viewpager --- .../wallets/activity/AllActivityScreen.kt | 53 +++++++++++++------ 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/activity/AllActivityScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/activity/AllActivityScreen.kt index d0d98f84f..ade63ce7b 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/activity/AllActivityScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/activity/AllActivityScreen.kt @@ -3,9 +3,14 @@ package to.bitkit.ui.screens.wallets.activity import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.pager.HorizontalPager +import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.key +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource @@ -18,6 +23,7 @@ import kotlinx.collections.immutable.ImmutableSet import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentSetOf import kotlinx.collections.immutable.toImmutableList +import kotlinx.coroutines.launch import to.bitkit.R import to.bitkit.ui.appViewModel import to.bitkit.ui.components.PinnedTabsScaffold @@ -28,7 +34,6 @@ import to.bitkit.ui.screens.wallets.activity.components.ActivityListFilter import to.bitkit.ui.screens.wallets.activity.components.ActivityListGrouped import to.bitkit.ui.screens.wallets.activity.components.ActivityTab import to.bitkit.ui.screens.wallets.activity.utils.previewActivityItems -import to.bitkit.ui.shared.modifiers.swipeToChangeTab import to.bitkit.ui.shared.util.screen import to.bitkit.ui.theme.AppThemeSurface import to.bitkit.viewmodels.ActivityListViewModel @@ -88,6 +93,23 @@ private fun AllActivityScreenContent( onActivityItemClick: (String) -> Unit, onEmptyActivityRowClick: () -> Unit, ) { + val pagerState = rememberPagerState( + initialPage = currentTabIndex, + pageCount = { tabs.size }, + ) + val scope = rememberCoroutineScope() + + LaunchedEffect(pagerState.currentPage) { + if (pagerState.currentPage != currentTabIndex) { + onTabChange(pagerState.currentPage) + } + } + LaunchedEffect(currentTabIndex) { + if (currentTabIndex != pagerState.currentPage) { + pagerState.animateScrollToPage(currentTabIndex) + } + } + Column( modifier = Modifier.screen() ) { @@ -111,26 +133,25 @@ private fun AllActivityScreenContent( onRemoveTag = onRemoveTag, onDateRangeClick = onDateRangeClick, tabs = tabs, - currentTabIndex = currentTabIndex, - onTabChange = { onTabChange(tabs.indexOf(it)) }, + currentTabIndex = pagerState.currentPage, + onTabChange = { tab -> scope.launch { pagerState.animateScrollToPage(tabs.indexOf(tab)) } }, modifier = Modifier.padding(horizontal = 16.dp) ) } ) { topPadding -> - ActivityListGrouped( - items = filteredActivities, - onActivityItemClick = onActivityItemClick, - onEmptyActivityRowClick = onEmptyActivityRowClick, - contentPadding = PaddingValues(top = topPadding), - modifier = Modifier - .swipeToChangeTab( - currentTabIndex = currentTabIndex, - tabCount = tabs.size, - onTabChange = onTabChange, + HorizontalPager(state = pagerState) { _ -> + key(currentTabIndex) { + ActivityListGrouped( + items = filteredActivities, + onActivityItemClick = onActivityItemClick, + onEmptyActivityRowClick = onEmptyActivityRowClick, + contentPadding = PaddingValues(top = topPadding + 16.dp), + modifier = Modifier + .padding(horizontal = 16.dp) + .testTag("ActivityList") ) - .padding(horizontal = 16.dp) - .testTag("ActivityList") - ) + } + } } } } From f37d9e6fbf78b48366e6630809723877cd046d70 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Mon, 25 May 2026 13:37:33 -0300 Subject: [PATCH 06/15] fix: remove viewpager --- .../wallets/activity/AllActivityScreen.kt | 53 ++++++------------- 1 file changed, 16 insertions(+), 37 deletions(-) diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/activity/AllActivityScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/activity/AllActivityScreen.kt index ade63ce7b..15fd1e5c4 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/activity/AllActivityScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/activity/AllActivityScreen.kt @@ -3,14 +3,9 @@ package to.bitkit.ui.screens.wallets.activity import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.pager.HorizontalPager -import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue -import androidx.compose.runtime.key -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource @@ -23,7 +18,6 @@ import kotlinx.collections.immutable.ImmutableSet import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentSetOf import kotlinx.collections.immutable.toImmutableList -import kotlinx.coroutines.launch import to.bitkit.R import to.bitkit.ui.appViewModel import to.bitkit.ui.components.PinnedTabsScaffold @@ -34,6 +28,7 @@ import to.bitkit.ui.screens.wallets.activity.components.ActivityListFilter import to.bitkit.ui.screens.wallets.activity.components.ActivityListGrouped import to.bitkit.ui.screens.wallets.activity.components.ActivityTab import to.bitkit.ui.screens.wallets.activity.utils.previewActivityItems +import to.bitkit.ui.shared.modifiers.swipeToChangeTab import to.bitkit.ui.shared.util.screen import to.bitkit.ui.theme.AppThemeSurface import to.bitkit.viewmodels.ActivityListViewModel @@ -93,23 +88,6 @@ private fun AllActivityScreenContent( onActivityItemClick: (String) -> Unit, onEmptyActivityRowClick: () -> Unit, ) { - val pagerState = rememberPagerState( - initialPage = currentTabIndex, - pageCount = { tabs.size }, - ) - val scope = rememberCoroutineScope() - - LaunchedEffect(pagerState.currentPage) { - if (pagerState.currentPage != currentTabIndex) { - onTabChange(pagerState.currentPage) - } - } - LaunchedEffect(currentTabIndex) { - if (currentTabIndex != pagerState.currentPage) { - pagerState.animateScrollToPage(currentTabIndex) - } - } - Column( modifier = Modifier.screen() ) { @@ -133,25 +111,26 @@ private fun AllActivityScreenContent( onRemoveTag = onRemoveTag, onDateRangeClick = onDateRangeClick, tabs = tabs, - currentTabIndex = pagerState.currentPage, - onTabChange = { tab -> scope.launch { pagerState.animateScrollToPage(tabs.indexOf(tab)) } }, + currentTabIndex = currentTabIndex, + onTabChange = { onTabChange(tabs.indexOf(it)) }, modifier = Modifier.padding(horizontal = 16.dp) ) } ) { topPadding -> - HorizontalPager(state = pagerState) { _ -> - key(currentTabIndex) { - ActivityListGrouped( - items = filteredActivities, - onActivityItemClick = onActivityItemClick, - onEmptyActivityRowClick = onEmptyActivityRowClick, - contentPadding = PaddingValues(top = topPadding + 16.dp), - modifier = Modifier - .padding(horizontal = 16.dp) - .testTag("ActivityList") + ActivityListGrouped( + items = filteredActivities, + onActivityItemClick = onActivityItemClick, + onEmptyActivityRowClick = onEmptyActivityRowClick, + contentPadding = PaddingValues(top = topPadding + 16.dp), + modifier = Modifier + .swipeToChangeTab( + currentTabIndex = currentTabIndex, + tabCount = tabs.size, + onTabChange = onTabChange, ) - } - } + .padding(horizontal = 16.dp) + .testTag("ActivityList") + ) } } } From 3c24dbe8c02659095588e1ccae1dbde9fb738549 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Mon, 25 May 2026 13:45:34 -0300 Subject: [PATCH 07/15] fix: apply blur bg to the tab --- .../bitkit/ui/components/PinnedTabsScaffold.kt | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/to/bitkit/ui/components/PinnedTabsScaffold.kt b/app/src/main/java/to/bitkit/ui/components/PinnedTabsScaffold.kt index 31c3d8280..9de397264 100644 --- a/app/src/main/java/to/bitkit/ui/components/PinnedTabsScaffold.kt +++ b/app/src/main/java/to/bitkit/ui/components/PinnedTabsScaffold.kt @@ -22,7 +22,11 @@ import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.zIndex +import dev.chrisbanes.haze.hazeEffect +import dev.chrisbanes.haze.hazeSource +import dev.chrisbanes.haze.rememberHazeState import to.bitkit.ui.theme.Colors +import to.bitkit.ui.theme.TopBarGradient private val PinnedTabsShadowHeight = 32.dp @@ -32,6 +36,7 @@ fun PinnedTabsScaffold( modifier: Modifier = Modifier, content: @Composable (topPadding: Dp) -> Unit, ) { + val hazeState = rememberHazeState() val density = LocalDensity.current var headerHeight by remember { mutableStateOf(0.dp) } val shadowBrush = remember { @@ -39,7 +44,13 @@ fun PinnedTabsScaffold( } Box(modifier = modifier.fillMaxSize()) { - content(headerHeight) + Box( + modifier = Modifier + .fillMaxSize() + .hazeSource(hazeState) + ) { + content(headerHeight) + } Box( modifier = Modifier @@ -54,8 +65,9 @@ fun PinnedTabsScaffold( modifier = Modifier .align(Alignment.TopStart) .fillMaxWidth() - .background(Colors.Black) .zIndex(2f) + .hazeEffect(state = hazeState) + .background(TopBarGradient) .onSizeChanged { headerHeight = with(density) { it.height.toDp() } } ) { header() From 43b371bbf58b225085c3282793b8945c3195525e Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Mon, 25 May 2026 14:09:15 -0300 Subject: [PATCH 08/15] fix: apply blur to AppTopBar --- .../shop/shopDiscover/ShopDiscoverScreen.kt | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 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 503046b68..623b4c3be 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 @@ -74,21 +74,23 @@ fun ShopDiscoverScreen( val scope = rememberCoroutineScope() ScreenColumn(modifier = modifier) { - AppTopBar( - titleText = stringResource(R.string.other__shop__discover__nav_title), - onBackClick = onBack, - actions = { DrawerNavIcon() }, - ) - PinnedTabsScaffold( header = { - CustomTabRowWithSpacing( - tabs = tabs, - currentTabIndex = pagerState.currentPage, - selectedColor = Colors.White, - onTabChange = { scope.launch { pagerState.animateScrollToPage(tabs.indexOf(it)) } }, - modifier = Modifier.padding(horizontal = 16.dp) - ) + Column(modifier = modifier.fillMaxWidth()) { + AppTopBar( + titleText = stringResource(R.string.other__shop__discover__nav_title), + onBackClick = onBack, + actions = { DrawerNavIcon() }, + ) + + CustomTabRowWithSpacing( + tabs = tabs, + currentTabIndex = pagerState.currentPage, + selectedColor = Colors.White, + onTabChange = { scope.launch { pagerState.animateScrollToPage(tabs.indexOf(it)) } }, + modifier = Modifier.padding(horizontal = 16.dp) + ) + } } ) { topPadding -> HorizontalPager( From e93c06be4e629b1f0a3d8f95bf8c8a2ba85b29aa Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Mon, 25 May 2026 14:15:08 -0300 Subject: [PATCH 09/15] fix: apply default bg color --- .../to/bitkit/ui/components/PinnedTabsScaffold.kt | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/to/bitkit/ui/components/PinnedTabsScaffold.kt b/app/src/main/java/to/bitkit/ui/components/PinnedTabsScaffold.kt index 9de397264..f52bcbad1 100644 --- a/app/src/main/java/to/bitkit/ui/components/PinnedTabsScaffold.kt +++ b/app/src/main/java/to/bitkit/ui/components/PinnedTabsScaffold.kt @@ -22,13 +22,15 @@ import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.zIndex +import dev.chrisbanes.haze.HazeStyle +import dev.chrisbanes.haze.HazeTint import dev.chrisbanes.haze.hazeEffect import dev.chrisbanes.haze.hazeSource import dev.chrisbanes.haze.rememberHazeState import to.bitkit.ui.theme.Colors -import to.bitkit.ui.theme.TopBarGradient private val PinnedTabsShadowHeight = 32.dp +private val PinnedTabsBlurRadius = 24.dp @Composable fun PinnedTabsScaffold( @@ -42,6 +44,13 @@ fun PinnedTabsScaffold( val shadowBrush = remember { Brush.verticalGradient(colors = listOf(Colors.Black, Color.Transparent)) } + val hazeStyle = remember { + HazeStyle( + backgroundColor = Colors.Black, + tint = HazeTint(Colors.Black50), + blurRadius = PinnedTabsBlurRadius, + ) + } Box(modifier = modifier.fillMaxSize()) { Box( @@ -66,8 +75,7 @@ fun PinnedTabsScaffold( .align(Alignment.TopStart) .fillMaxWidth() .zIndex(2f) - .hazeEffect(state = hazeState) - .background(TopBarGradient) + .hazeEffect(state = hazeState, style = hazeStyle) .onSizeChanged { headerHeight = with(density) { it.height.toDp() } } ) { header() From 2b6f7822d74b076f1a2b6132d0d68a1791c6bd51 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Mon, 25 May 2026 14:21:34 -0300 Subject: [PATCH 10/15] fix: bg transparency --- app/src/main/java/to/bitkit/ui/components/PinnedTabsScaffold.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/to/bitkit/ui/components/PinnedTabsScaffold.kt b/app/src/main/java/to/bitkit/ui/components/PinnedTabsScaffold.kt index f52bcbad1..0398a829a 100644 --- a/app/src/main/java/to/bitkit/ui/components/PinnedTabsScaffold.kt +++ b/app/src/main/java/to/bitkit/ui/components/PinnedTabsScaffold.kt @@ -47,7 +47,7 @@ fun PinnedTabsScaffold( val hazeStyle = remember { HazeStyle( backgroundColor = Colors.Black, - tint = HazeTint(Colors.Black50), + tint = HazeTint(Colors.Black70), blurRadius = PinnedTabsBlurRadius, ) } From f2462cf79691510f87e7f9bc92fab2b2265441b7 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Mon, 25 May 2026 14:34:29 -0300 Subject: [PATCH 11/15] fix: recompose on tab change --- .../wallets/activity/AllActivityScreen.kt | 31 ++++++++++--------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/activity/AllActivityScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/activity/AllActivityScreen.kt index 15fd1e5c4..c03101b37 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/activity/AllActivityScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/activity/AllActivityScreen.kt @@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue +import androidx.compose.runtime.key import androidx.compose.ui.Modifier import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource @@ -117,20 +118,22 @@ private fun AllActivityScreenContent( ) } ) { topPadding -> - ActivityListGrouped( - items = filteredActivities, - onActivityItemClick = onActivityItemClick, - onEmptyActivityRowClick = onEmptyActivityRowClick, - contentPadding = PaddingValues(top = topPadding + 16.dp), - modifier = Modifier - .swipeToChangeTab( - currentTabIndex = currentTabIndex, - tabCount = tabs.size, - onTabChange = onTabChange, - ) - .padding(horizontal = 16.dp) - .testTag("ActivityList") - ) + key(currentTabIndex) { + ActivityListGrouped( + items = filteredActivities, + onActivityItemClick = onActivityItemClick, + onEmptyActivityRowClick = onEmptyActivityRowClick, + contentPadding = PaddingValues(top = topPadding + 16.dp), + modifier = Modifier + .swipeToChangeTab( + currentTabIndex = currentTabIndex, + tabCount = tabs.size, + onTabChange = onTabChange, + ) + .padding(horizontal = 16.dp) + .testTag("ActivityList") + ) + } } } } From c89dd8837cb4f2d89d6932ff0025d9d697881229 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Mon, 25 May 2026 14:43:25 -0300 Subject: [PATCH 12/15] fix: scroll to top on tab change --- .../wallets/activity/AllActivityScreen.kt | 40 +++++++++++-------- .../components/ActivityListGrouped.kt | 4 ++ 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/activity/AllActivityScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/activity/AllActivityScreen.kt index c03101b37..d071d72eb 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/activity/AllActivityScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/activity/AllActivityScreen.kt @@ -3,10 +3,11 @@ package to.bitkit.ui.screens.wallets.activity import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue -import androidx.compose.runtime.key import androidx.compose.ui.Modifier import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource @@ -89,6 +90,12 @@ private fun AllActivityScreenContent( onActivityItemClick: (String) -> Unit, onEmptyActivityRowClick: () -> Unit, ) { + val listState = rememberLazyListState() + + LaunchedEffect(currentTabIndex) { + listState.scrollToItem(0) + } + Column( modifier = Modifier.screen() ) { @@ -118,22 +125,21 @@ private fun AllActivityScreenContent( ) } ) { topPadding -> - key(currentTabIndex) { - ActivityListGrouped( - items = filteredActivities, - onActivityItemClick = onActivityItemClick, - onEmptyActivityRowClick = onEmptyActivityRowClick, - contentPadding = PaddingValues(top = topPadding + 16.dp), - modifier = Modifier - .swipeToChangeTab( - currentTabIndex = currentTabIndex, - tabCount = tabs.size, - onTabChange = onTabChange, - ) - .padding(horizontal = 16.dp) - .testTag("ActivityList") - ) - } + ActivityListGrouped( + items = filteredActivities, + onActivityItemClick = onActivityItemClick, + onEmptyActivityRowClick = onEmptyActivityRowClick, + listState = listState, + contentPadding = PaddingValues(top = topPadding + 16.dp), + modifier = Modifier + .swipeToChangeTab( + currentTabIndex = currentTabIndex, + tabCount = tabs.size, + onTabChange = onTabChange, + ) + .padding(horizontal = 16.dp) + .testTag("ActivityList") + ) } } } diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/activity/components/ActivityListGrouped.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/activity/components/ActivityListGrouped.kt index f74e38850..c7247aecb 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/activity/components/ActivityListGrouped.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/activity/components/ActivityListGrouped.kt @@ -9,7 +9,9 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.wrapContentWidth import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyListScope +import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -46,6 +48,7 @@ fun ActivityListGrouped( onActivityItemClick: (String) -> Unit, onEmptyActivityRowClick: () -> Unit, modifier: Modifier = Modifier, + listState: LazyListState = rememberLazyListState(), showFooter: Boolean = false, onAllActivityButtonClick: () -> Unit = {}, contentPadding: PaddingValues = PaddingValues(top = 20.dp), @@ -65,6 +68,7 @@ fun ActivityListGrouped( val groupedItems = groupActivityItems(items) LazyColumn( + state = listState, horizontalAlignment = Alignment.CenterHorizontally, contentPadding = contentPadding, modifier = Modifier.fillMaxWidth() From 5d338e3a257575e0db8458d773c0c4b9115c1e01 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Tue, 26 May 2026 08:54:06 -0300 Subject: [PATCH 13/15] fix: apply padding to empty state text --- .../screens/wallets/activity/components/ActivityListGrouped.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/activity/components/ActivityListGrouped.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/activity/components/ActivityListGrouped.kt index c7247aecb..c33e2d074 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/activity/components/ActivityListGrouped.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/activity/components/ActivityListGrouped.kt @@ -150,6 +150,7 @@ fun ActivityListGrouped( color = Colors.White64, modifier = Modifier .fillMaxWidth() + .padding(contentPadding) .padding(16.dp) ) } From 655c6c75227afa9ee9e106f13cdbc3c427d63116 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Tue, 26 May 2026 08:55:30 -0300 Subject: [PATCH 14/15] fix: modifier reuse --- .../bitkit/ui/screens/shop/shopDiscover/ShopDiscoverScreen.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 623b4c3be..5d38822a8 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 @@ -76,7 +76,7 @@ fun ShopDiscoverScreen( ScreenColumn(modifier = modifier) { PinnedTabsScaffold( header = { - Column(modifier = modifier.fillMaxWidth()) { + Column(modifier = Modifier.fillMaxWidth()) { AppTopBar( titleText = stringResource(R.string.other__shop__discover__nav_title), onBackClick = onBack, From 4956d2278c830ff3d4007d71bf286f82d76058d1 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Tue, 26 May 2026 09:14:15 -0300 Subject: [PATCH 15/15] fix: implement subcompose for measure calculation to avoid recomposition --- .../ui/components/PinnedTabsScaffold.kt | 74 ++++++++++--------- 1 file changed, 39 insertions(+), 35 deletions(-) diff --git a/app/src/main/java/to/bitkit/ui/components/PinnedTabsScaffold.kt b/app/src/main/java/to/bitkit/ui/components/PinnedTabsScaffold.kt index 0398a829a..44c510d3c 100644 --- a/app/src/main/java/to/bitkit/ui/components/PinnedTabsScaffold.kt +++ b/app/src/main/java/to/bitkit/ui/components/PinnedTabsScaffold.kt @@ -7,21 +7,14 @@ import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.offset import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color -import androidx.compose.ui.layout.onSizeChanged -import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.layout.SubcomposeLayout import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp -import androidx.compose.ui.zIndex import dev.chrisbanes.haze.HazeStyle import dev.chrisbanes.haze.HazeTint import dev.chrisbanes.haze.hazeEffect @@ -32,6 +25,8 @@ import to.bitkit.ui.theme.Colors private val PinnedTabsShadowHeight = 32.dp private val PinnedTabsBlurRadius = 24.dp +private enum class PinnedTabsSlot { Header, Content, Shadow } + @Composable fun PinnedTabsScaffold( header: @Composable ColumnScope.() -> Unit, @@ -39,8 +34,6 @@ fun PinnedTabsScaffold( content: @Composable (topPadding: Dp) -> Unit, ) { val hazeState = rememberHazeState() - val density = LocalDensity.current - var headerHeight by remember { mutableStateOf(0.dp) } val shadowBrush = remember { Brush.verticalGradient(colors = listOf(Colors.Black, Color.Transparent)) } @@ -52,33 +45,44 @@ fun PinnedTabsScaffold( ) } - Box(modifier = modifier.fillMaxSize()) { - Box( - modifier = Modifier - .fillMaxSize() - .hazeSource(hazeState) - ) { - content(headerHeight) - } + SubcomposeLayout(modifier = modifier.fillMaxSize()) { constraints -> + val looseConstraints = constraints.copy(minWidth = 0, minHeight = 0) - Box( - modifier = Modifier - .fillMaxWidth() - .offset(y = headerHeight) - .height(PinnedTabsShadowHeight) - .background(shadowBrush) - .zIndex(1f) - ) + val headerPlaceables = subcompose(PinnedTabsSlot.Header) { + Column( + modifier = Modifier + .fillMaxWidth() + .hazeEffect(state = hazeState, style = hazeStyle), + content = { header() }, + ) + }.map { it.measure(looseConstraints) } + + val headerHeightPx = headerPlaceables.maxOfOrNull { it.height } ?: 0 + val headerHeightDp = headerHeightPx.toDp() + + val contentPlaceables = subcompose(PinnedTabsSlot.Content) { + Box( + modifier = Modifier + .fillMaxSize() + .hazeSource(hazeState) + ) { + content(headerHeightDp) + } + }.map { it.measure(constraints) } + + val shadowPlaceables = subcompose(PinnedTabsSlot.Shadow) { + Box( + modifier = Modifier + .fillMaxWidth() + .height(PinnedTabsShadowHeight) + .background(shadowBrush) + ) + }.map { it.measure(looseConstraints) } - Column( - modifier = Modifier - .align(Alignment.TopStart) - .fillMaxWidth() - .zIndex(2f) - .hazeEffect(state = hazeState, style = hazeStyle) - .onSizeChanged { headerHeight = with(density) { it.height.toDp() } } - ) { - header() + layout(constraints.maxWidth, constraints.maxHeight) { + contentPlaceables.forEach { it.placeRelative(0, 0) } + shadowPlaceables.forEach { it.placeRelative(0, headerHeightPx) } + headerPlaceables.forEach { it.placeRelative(0, 0) } } } }