@@ -8,6 +8,7 @@ import androidx.compose.foundation.gestures.snapping.rememberSnapFlingBehavior
88import androidx.compose.foundation.layout.Arrangement
99import androidx.compose.foundation.layout.Box
1010import androidx.compose.foundation.layout.Column
11+ import androidx.compose.foundation.layout.PaddingValues
1112import androidx.compose.foundation.layout.Row
1213import androidx.compose.foundation.layout.Spacer
1314import androidx.compose.foundation.layout.fillMaxHeight
@@ -27,12 +28,13 @@ import androidx.compose.material3.ExperimentalMaterial3Api
2728import androidx.compose.material3.Icon
2829import androidx.compose.material3.rememberTooltipState
2930import androidx.compose.runtime.Composable
30- import androidx.compose.runtime.derivedStateOf
31+ import androidx.compose.runtime.LaunchedEffect
3132import androidx.compose.runtime.getValue
3233import androidx.compose.runtime.mutableStateOf
3334import androidx.compose.runtime.remember
3435import androidx.compose.runtime.rememberCoroutineScope
3536import androidx.compose.runtime.setValue
37+ import androidx.compose.runtime.snapshotFlow
3638import androidx.compose.ui.Alignment
3739import androidx.compose.ui.Modifier
3840import androidx.compose.ui.draw.clip
@@ -47,6 +49,8 @@ import androidx.compose.ui.res.stringResource
4749import androidx.compose.ui.tooling.preview.Devices.NEXUS_5
4850import androidx.compose.ui.tooling.preview.Preview
4951import androidx.compose.ui.unit.dp
52+ import kotlinx.coroutines.FlowPreview
53+ import kotlinx.coroutines.flow.distinctUntilChanged
5054import kotlinx.coroutines.launch
5155import org.lightningdevkit.ldknode.ChannelDetails
5256import to.bitkit.R
@@ -65,6 +69,9 @@ import to.bitkit.ui.components.Tooltip
6569import to.bitkit.ui.components.VerticalSpacer
6670import to.bitkit.ui.scaffold.SheetTopBar
6771import to.bitkit.ui.screens.wallets.activity.components.CustomTabRowWithSpacing
72+ import to.bitkit.ui.screens.wallets.receive.ReceiveTab.AUTO
73+ import to.bitkit.ui.screens.wallets.receive.ReceiveTab.SAVINGS
74+ import to.bitkit.ui.screens.wallets.receive.ReceiveTab.SPENDING
6875import to.bitkit.ui.shared.effects.SetMaxBrightness
6976import to.bitkit.ui.shared.modifiers.sheetHeight
7077import to.bitkit.ui.shared.util.gradientBackground
@@ -76,6 +83,7 @@ import to.bitkit.ui.theme.Colors
7683import to.bitkit.ui.utils.withAccent
7784import to.bitkit.viewmodels.MainUiState
7885
86+ @OptIn(FlowPreview ::class )
7987@Composable
8088fun ReceiveQrScreen (
8189 cjitInvoice : String? ,
@@ -122,58 +130,39 @@ fun ReceiveQrScreen(
122130 }
123131 }
124132
125- // Determine initial tab index
126- val initialTabIndex = remember(initialTab, visibleTabs) {
127- if (initialTab != null ) {
128- visibleTabs.indexOf(initialTab).coerceAtLeast(0 )
129- } else {
130- when {
131- ! cjitInvoice.isNullOrEmpty() -> visibleTabs.indexOf(ReceiveTab .SPENDING )
132- hasUsableChannels -> visibleTabs.indexOf(ReceiveTab .AUTO )
133- else -> visibleTabs.indexOf(ReceiveTab .SAVINGS )
134- }.coerceAtLeast(0 )
135- }
136- }
137-
138133 // LazyRow state with snap behavior
139134 val scope = rememberCoroutineScope()
140- val lazyListState = rememberLazyListState(
141- initialFirstVisibleItemIndex = initialTabIndex
142- )
135+ val lazyListState = rememberLazyListState()
143136
144137 val snapBehavior = rememberSnapFlingBehavior(
145138 lazyListState = lazyListState,
146139 snapPosition = SnapPosition .Center
147140 )
148141
149142 // Calculate current tab based on scroll position for smooth indicator and color updates
150- val selectedTab by remember {
151- derivedStateOf {
152- val layoutInfo = lazyListState.layoutInfo
153- val currentIndex = if (layoutInfo.visibleItemsInfo.isEmpty()) {
154- lazyListState.firstVisibleItemIndex
155- } else {
156- val viewportMidpoint = layoutInfo.viewportStartOffset +
157- (layoutInfo.viewportEndOffset - layoutInfo.viewportStartOffset) / 2
158-
159- layoutInfo.visibleItemsInfo
160- .minByOrNull { item ->
161- val itemMidpoint = item.offset + item.size / 2
162- kotlin.math.abs(itemMidpoint - viewportMidpoint)
163- }
164- ?.index ? : lazyListState.firstVisibleItemIndex
165- }
143+ var selectedTab by remember {
144+ mutableStateOf(initialTab ? : ReceiveTab .SAVINGS )
145+ }
166146
167- visibleTabs.getOrNull(currentIndex)
168- ? : visibleTabs.firstOrNull()
169- ? : ReceiveTab .SAVINGS
170- }
147+ LaunchedEffect (lazyListState, visibleTabs.size) {
148+ snapshotFlow { lazyListState.firstVisibleItemIndex }
149+ .distinctUntilChanged()
150+ .collect { index ->
151+ if (index < visibleTabs.size && index > - 1 ) {
152+ val tab = visibleTabs[index]
153+ selectedTab = tab
154+ }
155+ }
171156 }
172157
173- // Derive index from selectedTab for tab row indicator
174- val currentTabIndex by remember {
175- derivedStateOf {
176- visibleTabs.indexOf(selectedTab).coerceAtLeast(0 )
158+ // Auto-switch to AUTO tab when it becomes available for the first time
159+ LaunchedEffect (hasUsableChannels) {
160+ if (hasUsableChannels && visibleTabs.contains(ReceiveTab .AUTO )) {
161+ val autoIndex = visibleTabs.indexOf(ReceiveTab .AUTO )
162+ if (autoIndex != - 1 ) {
163+ lazyListState.animateScrollToItem(autoIndex)
164+ selectedTab = ReceiveTab .AUTO
165+ }
177166 }
178167 }
179168
@@ -191,23 +180,27 @@ fun ReceiveQrScreen(
191180 .keepScreenOn()
192181 ) {
193182 SheetTopBar (stringResource(R .string.wallet__receive_bitcoin))
194- Column (
195- modifier = Modifier .padding(horizontal = 16 .dp)
196- ) {
183+ Column {
197184 Spacer (Modifier .height(16 .dp))
198185
199186 // Tab row
200187 CustomTabRowWithSpacing (
201188 tabs = visibleTabs,
202- currentTabIndex = currentTabIndex,
203- selectedColor = selectedTab.accentColor,
189+ currentTabIndex = visibleTabs.indexOf(selectedTab),
190+ selectedColor = when (selectedTab) {
191+ SAVINGS -> Colors .Brand
192+ AUTO -> Colors .White
193+ SPENDING -> Colors .Purple
194+ },
204195 onTabChange = { tab ->
205196 haptic.performHapticFeedback(HapticFeedbackType .TextHandleMove )
206197 val newIndex = visibleTabs.indexOf(tab)
198+ selectedTab = tab
207199 scope.launch {
208200 lazyListState.animateScrollToItem(newIndex)
209201 }
210- }
202+ },
203+ modifier = Modifier .padding(horizontal = 16 .dp)
211204 )
212205
213206 Spacer (Modifier .height(24 .dp))
@@ -217,6 +210,7 @@ fun ReceiveQrScreen(
217210 state = lazyListState,
218211 flingBehavior = snapBehavior,
219212 horizontalArrangement = Arrangement .spacedBy(16 .dp),
213+ contentPadding = PaddingValues (horizontal = 16 .dp),
220214 userScrollEnabled = true ,
221215 modifier = Modifier
222216 .weight(1f )
@@ -299,13 +293,15 @@ fun ReceiveQrScreen(
299293 }
300294 },
301295 fullWidth = true ,
302- modifier = Modifier .testTag(
303- if (showDetails) {
304- " QRCode"
305- } else {
306- " ShowDetails"
307- }
308- )
296+ modifier = Modifier
297+ .padding(horizontal = 16 .dp)
298+ .testTag(
299+ if (showDetails) {
300+ " QRCode"
301+ } else {
302+ " ShowDetails"
303+ }
304+ )
309305 )
310306 }
311307
0 commit comments