From dc838d1af9d275a7fe83813a3947b536dbc97339 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 20 Oct 2026 03:54:50 +0200 Subject: [PATCH 1/7] fix: slide receive tabs on wraparound --- .../to/bitkit/ui/components/QrCodeImage.kt | 17 ++++- .../wallets/receive/ReceiveQrScreen.kt | 73 +++++++++++++------ .../modifiers/SwipeToChangeTabModifier.kt | 69 ------------------ changelog.d/next/receive-wrap-slide.fixed.md | 1 + journeys/receive/receive-tabs-wraparound.xml | 7 +- 5 files changed, 71 insertions(+), 96 deletions(-) create mode 100644 changelog.d/next/receive-wrap-slide.fixed.md diff --git a/app/src/main/java/to/bitkit/ui/components/QrCodeImage.kt b/app/src/main/java/to/bitkit/ui/components/QrCodeImage.kt index 504399d2d4..4d9dd08bff 100644 --- a/app/src/main/java/to/bitkit/ui/components/QrCodeImage.kt +++ b/app/src/main/java/to/bitkit/ui/components/QrCodeImage.kt @@ -1,6 +1,7 @@ package to.bitkit.ui.components import android.graphics.Bitmap +import android.util.LruCache import androidx.compose.animation.Crossfade import androidx.compose.animation.core.tween import androidx.compose.foundation.Image @@ -50,6 +51,14 @@ import to.bitkit.ui.theme.AppShapes import to.bitkit.ui.theme.AppThemeSurface import to.bitkit.ui.theme.Colors +/** Memory budget for generated QR bitmaps kept for reuse */ +private const val QR_BITMAP_CACHE_BYTES = 16 * 1024 * 1024 + +/** Generated QR bitmaps by size and content, so a code composed again draws at once instead of loading */ +private val qrBitmapCache = object : LruCache(QR_BITMAP_CACHE_BYTES) { + override fun sizeOf(key: String, value: Bitmap) = value.byteCount +} + private const val QUIET_ZONE_MIN = 2 private const val QUIET_ZONE_MAX = 4 private const val QUIET_ZONE_RATIO = 150 @@ -160,10 +169,15 @@ fun QrCodeImage( internal fun rememberQrBitmap(content: String, size: Dp): Bitmap? { if (content.isEmpty()) return null - var bitmap by remember(content) { mutableStateOf(null) } val sizePx = with(LocalDensity.current) { size.roundToPx() } + val cacheKey = "$sizePx:$content" + var bitmap by remember(content) { mutableStateOf(qrBitmapCache.get(cacheKey)) } LaunchedEffect(content, size) { + qrBitmapCache.get(cacheKey)?.let { + bitmap = it + return@LaunchedEffect + } bitmap = null // Always reset to show loading indicator launch(Dispatchers.Default) { @@ -204,6 +218,7 @@ internal fun rememberQrBitmap(content: String, size: Dp): Bitmap? { newBitmap.setPixels(pixels, 0, matrixWidth, 0, 0, matrixWidth, matrixHeight) + qrBitmapCache.put(cacheKey, newBitmap) bitmap = newBitmap } } diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt index a9174450c1..061a195748 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt @@ -36,6 +36,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshotFlow +import androidx.compose.runtime.withFrameNanos import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -59,6 +60,7 @@ import kotlinx.collections.immutable.persistentMapOf import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.filter import kotlinx.coroutines.launch import org.lightningdevkit.ldknode.ChannelDetails import to.bitkit.R @@ -88,7 +90,6 @@ import to.bitkit.ui.screens.wallets.activity.components.CustomTabRowWithSpacing import to.bitkit.ui.screens.wallets.usdt.UsdtDepositReceiveScreen import to.bitkit.ui.shared.effects.SetMaxBrightness import to.bitkit.ui.shared.modifiers.sheetHeight -import to.bitkit.ui.shared.modifiers.swipePastEdges import to.bitkit.ui.shared.util.gradientBackground import to.bitkit.ui.shared.util.shareQrCode import to.bitkit.ui.shared.util.shareText @@ -192,10 +193,13 @@ fun ReceiveQrScreen( } } - // LazyRow state with snap behavior + // LazyRow state with snap behavior; the pages wrap each end with a copy of the tab at the other end val scope = rememberCoroutineScope() + val receivePages = remember(visibleTabs) { + (listOf(visibleTabs.last()) + visibleTabs + visibleTabs.first()).toImmutableList() + } val lazyListState = rememberLazyListState( - initialFirstVisibleItemIndex = visibleTabs.indexOf(defaultTab).coerceAtLeast(0), + initialFirstVisibleItemIndex = visibleTabs.pageIndexOf(defaultTab), ) val snapBehavior = rememberSnapFlingBehavior( @@ -219,14 +223,14 @@ fun ReceiveQrScreen( appliedInitialTab = requestedTab requestedTab?.let { selectedTab = it - lazyListState.scrollToItem(visibleTabs.indexOf(it)) + lazyListState.scrollToItem(visibleTabs.pageIndexOf(it)) return@LaunchedEffect } } if (selectedTab !in visibleTabs) { val fallbackTab = visibleTabs.defaultReceiveTab() selectedTab = fallbackTab - lazyListState.scrollToItem(visibleTabs.indexOf(fallbackTab).coerceAtLeast(0)) + lazyListState.scrollToItem(visibleTabs.pageIndexOf(fallbackTab)) } } @@ -236,7 +240,7 @@ fun ReceiveQrScreen( } if (!canCreateLightningInvoice && cjitInvoice.isNullOrEmpty()) { selectedTab = ReceiveTab.SAVINGS - lazyListState.scrollToItem(visibleTabs.indexOf(ReceiveTab.SAVINGS).coerceAtLeast(0)) + lazyListState.scrollToItem(visibleTabs.pageIndexOf(ReceiveTab.SAVINGS)) } } @@ -244,10 +248,23 @@ fun ReceiveQrScreen( snapshotFlow { lazyListState.firstVisibleItemIndex } .distinctUntilChanged() .collect { index -> - if (selectedTab != ReceiveTab.USDT && index < visibleTabs.size && index > -1) { - val tab = visibleTabs[index] - selectedTab = tab + val tab = visibleTabs.getOrNull(index - 1) ?: return@collect + if (selectedTab != ReceiveTab.USDT) selectedTab = tab + } + } + + // Swap a settled wrap page for the tab it shows, so a swipe past either end slides on to the other end + LaunchedEffect(lazyListState, visibleTabs) { + snapshotFlow { lazyListState.isScrollInProgress } + .filter { !it } + .collect { + val tab = when (lazyListState.firstVisibleItemIndex) { + 0 -> visibleTabs.last() + visibleTabs.size + 1 -> visibleTabs.first() + else -> return@collect } + selectedTab = tab + lazyListState.scrollToItem(visibleTabs.pageIndexOf(tab)) } } @@ -267,18 +284,18 @@ fun ReceiveQrScreen( initialTab = initialTab, ) if (!shouldAutoSwitch) return@LaunchedEffect - val autoIndex = visibleTabs.indexOf(ReceiveTab.AUTO) - if (autoIndex == -1 || lazyListState.firstVisibleItemIndex == autoIndex) return@LaunchedEffect - lazyListState.scrollToItem(autoIndex) + if (ReceiveTab.AUTO !in visibleTabs) return@LaunchedEffect + val autoPage = visibleTabs.pageIndexOf(ReceiveTab.AUTO) + if (lazyListState.firstVisibleItemIndex == autoPage) return@LaunchedEffect + lazyListState.scrollToItem(autoPage) selectedTab = ReceiveTab.AUTO } // Auto-switch to Spending tab when CJIT is not null LaunchedEffect(cjitInvoice) { if (cjitInvoice != null) { - val spendingIndex = visibleTabs.indexOf(ReceiveTab.SPENDING) - if (spendingIndex != -1) { - lazyListState.animateScrollToItem(spendingIndex) + if (ReceiveTab.SPENDING in visibleTabs) { + lazyListState.animateScrollToItem(visibleTabs.pageIndexOf(ReceiveTab.SPENDING)) selectedTab = ReceiveTab.SPENDING } } @@ -298,9 +315,14 @@ fun ReceiveQrScreen( } fun selectReceiveTab(tab: ReceiveTab) { + val wrapsToFirst = selectedTab == visibleTabs.last() && tab == visibleTabs.first() selectedTab = tab hasUserSelectedTab = true - scope.launch { lazyListState.scrollToItem(visibleTabs.indexOf(tab)) } + scope.launch { + // The pager composes again when leaving USDT; let it lay out before sliding + repeat(2) { withFrameNanos {} } + lazyListState.animateScrollToItem(if (wrapsToFirst) visibleTabs.size + 1 else visibleTabs.pageIndexOf(tab)) + } } DisposableEffect(selectedTab) { @@ -365,7 +387,7 @@ fun ReceiveQrScreen( }, onTabChange = { tab -> haptic.performHapticFeedback(HapticFeedbackType.TextHandleMove) - val newIndex = visibleTabs.indexOf(tab) + val newIndex = visibleTabs.pageIndexOf(tab) hasUserSelectedTab = true selectedTab = tab showDetails = false @@ -388,15 +410,10 @@ fun ReceiveQrScreen( modifier = Modifier .weight(1f) .fillMaxWidth() - .swipePastEdges( - state = lazyListState, - onSwipePastStart = { selectReceiveTab(visibleTabs.last()) }, - onSwipePastEnd = { selectReceiveTab(visibleTabs.first()) }, - ) ) { itemsIndexed( - items = visibleTabs, - key = { _, tab -> tab.name } + items = receivePages, + key = { index, tab -> receivePageKey(index, tab, visibleTabs.size) } ) { _, tab -> val displayMode = getReceiveInvoiceDisplayMode( tab = tab, @@ -562,6 +579,14 @@ fun ReceiveQrScreen( } } +private fun List.pageIndexOf(tab: ReceiveTab): Int = indexOf(tab).coerceAtLeast(0) + 1 + +private fun receivePageKey(index: Int, tab: ReceiveTab, tabCount: Int): String = when (index) { + 0 -> "wrap-start-${tab.name}" + tabCount + 1 -> "wrap-end-${tab.name}" + else -> tab.name +} + private fun List.defaultReceiveTab(): ReceiveTab { return if (contains(ReceiveTab.AUTO)) ReceiveTab.AUTO else ReceiveTab.SAVINGS } diff --git a/app/src/main/java/to/bitkit/ui/shared/modifiers/SwipeToChangeTabModifier.kt b/app/src/main/java/to/bitkit/ui/shared/modifiers/SwipeToChangeTabModifier.kt index 1ff4571e87..76affc373c 100644 --- a/app/src/main/java/to/bitkit/ui/shared/modifiers/SwipeToChangeTabModifier.kt +++ b/app/src/main/java/to/bitkit/ui/shared/modifiers/SwipeToChangeTabModifier.kt @@ -1,24 +1,15 @@ package to.bitkit.ui.shared.modifiers -import androidx.compose.foundation.gestures.ScrollableState -import androidx.compose.foundation.gestures.awaitEachGesture -import androidx.compose.foundation.gestures.awaitFirstDown import androidx.compose.foundation.gestures.detectHorizontalDragGestures import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberUpdatedState import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.composed -import androidx.compose.ui.input.pointer.AwaitPointerEventScope -import androidx.compose.ui.input.pointer.PointerEventPass -import androidx.compose.ui.input.pointer.PointerInputChange import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.input.pointer.util.VelocityTracker import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.platform.LocalLayoutDirection -import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp import kotlin.math.abs @@ -89,66 +80,6 @@ private fun swipeTargetIndex(isPrevious: Boolean, currentTabIndex: Int, tabCount else -> null } -/** - * Reports a horizontal swipe that pushes past the first or last page of a scrollable pager, so the pager can wrap - * around. It only observes the pointer: the pager keeps handling and consuming its own drag. - * - * @param state The pager's scroll state, read when the swipe starts - * @param onSwipePastStart Callback invoked for a swipe toward the start on the first page (to the right in LTR) - * @param onSwipePastEnd Callback invoked for a swipe toward the end on the last page (to the left in LTR) - * @param velocityThreshold Velocity threshold in px/s (default: 600f) - * @param distanceThreshold Distance threshold in dp (default: 50.dp) - */ -fun Modifier.swipePastEdges( - state: ScrollableState, - onSwipePastStart: () -> Unit, - onSwipePastEnd: () -> Unit, - velocityThreshold: Float = DEFAULT_VELOCITY_THRESHOLD, - distanceThreshold: Float = DEFAULT_DISTANCE_THRESHOLD_DP, -): Modifier = composed { - val currentOnSwipePastStart by rememberUpdatedState(onSwipePastStart) - val currentOnSwipePastEnd by rememberUpdatedState(onSwipePastEnd) - val distanceThresholdPx = with(LocalDensity.current) { distanceThreshold.dp.toPx() } - val layoutDirection = LocalLayoutDirection.current - - pointerInput(state, layoutDirection) { - awaitEachGesture { - val down = awaitFirstDown(requireUnconsumed = false, pass = PointerEventPass.Initial) - val isAtStart = !state.canScrollBackward - val isAtEnd = !state.canScrollForward - if (!isAtStart && !isAtEnd) return@awaitEachGesture - - val velocityTracker = VelocityTracker() - velocityTracker.addPosition(down.uptimeMillis, down.position) - val up = awaitRelease(down, velocityTracker) ?: return@awaitEachGesture - - val drag = up.position - down.position - val isSwipe = abs(drag.x) > viewConfiguration.touchSlop && - abs(drag.x) > abs(drag.y) && - (abs(velocityTracker.calculateVelocity().x) >= velocityThreshold || abs(drag.x) >= distanceThresholdPx) - if (!isSwipe) return@awaitEachGesture - - // LazyRow scrolls the other way in RTL, so a swipe toward its start moves the finger left - val towardStart = if (layoutDirection == LayoutDirection.Rtl) drag.x < 0 else drag.x > 0 - when { - towardStart && isAtStart -> currentOnSwipePastStart() - !towardStart && isAtEnd -> currentOnSwipePastEnd() - } - } - } -} - -private suspend fun AwaitPointerEventScope.awaitRelease( - down: PointerInputChange, - velocityTracker: VelocityTracker, -): PointerInputChange? { - while (true) { - val change = awaitPointerEvent(PointerEventPass.Final).changes.firstOrNull { it.id == down.id } ?: return null - velocityTracker.addPosition(change.uptimeMillis, change.position) - if (!change.pressed) return change - } -} - // Reduced from 1500 to 600 for better iOS-like sensitivity private const val DEFAULT_VELOCITY_THRESHOLD = 600f diff --git a/changelog.d/next/receive-wrap-slide.fixed.md b/changelog.d/next/receive-wrap-slide.fixed.md new file mode 100644 index 0000000000..00f378a6a5 --- /dev/null +++ b/changelog.d/next/receive-wrap-slide.fixed.md @@ -0,0 +1 @@ +Swiping past the first or last Receive tab now slides to the other end like the other tabs. diff --git a/journeys/receive/receive-tabs-wraparound.xml b/journeys/receive/receive-tabs-wraparound.xml index 1fabf103d6..e1f74e5a32 100644 --- a/journeys/receive/receive-tabs-wraparound.xml +++ b/journeys/receive/receive-tabs-wraparound.xml @@ -1,7 +1,8 @@ On the Receive sheet, tab swipes wrap around: a swipe to the right on the first tab selects the - last tab, and a swipe to the left on the last tab selects the first. A sideways swipe never closes + last tab, and a swipe to the left on the last tab selects the first. The wrap slides on to the + other end the way a swipe between neighbouring tabs does. A sideways swipe never closes the Receive sheet, also when it is released above the sheet, and a tap on a QR still copies it. Precondition: onboarded dev wallet with USDT enabled (introductory sheet or Settings, General, @@ -12,7 +13,9 @@ Swipe with `adb shell input swipe` across the middle of the QR, about 60% of its width, in 300 ms (`adb shell input swipe 220 1176 860 1176 300` to the right on a 1080 px wide screen). A swipe that starts at the screen edge is the system back gesture, which closes the sheet on every - tab; start the swipes at least 100 px from the edge. + tab; start the swipes at least 100 px from the edge. The pager behind Savings, Auto and Spending + snaps back from a short synthetic swipe on the emulator, so swipe across it in 1200 ms + (`adb shell input swipe 150 1176 900 1176 1200`); the USDT QR takes the 300 ms swipe. Tap Receive (testTag "Receive") and verify the Savings tab (testTag "Tab-savings") is selected From dafe0047c6ce7e8c145f00a28646dffdfdb516af Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 20 Oct 2026 03:55:43 +0200 Subject: [PATCH 2/7] chore: rename changelog fragment --- changelog.d/next/{receive-wrap-slide.fixed.md => 1608.fixed.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename changelog.d/next/{receive-wrap-slide.fixed.md => 1608.fixed.md} (100%) diff --git a/changelog.d/next/receive-wrap-slide.fixed.md b/changelog.d/next/1608.fixed.md similarity index 100% rename from changelog.d/next/receive-wrap-slide.fixed.md rename to changelog.d/next/1608.fixed.md From 0624d16cec67b5ecc9e21075c7a1874727e7b5fa Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 20 Oct 2026 04:34:37 +0200 Subject: [PATCH 3/7] test: swipe the receive pager in 1200 ms in journey --- journeys/receive/receive-tabs-wraparound.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/journeys/receive/receive-tabs-wraparound.xml b/journeys/receive/receive-tabs-wraparound.xml index e1f74e5a32..2c11995ccc 100644 --- a/journeys/receive/receive-tabs-wraparound.xml +++ b/journeys/receive/receive-tabs-wraparound.xml @@ -21,8 +21,8 @@ Tap Receive (testTag "Receive") and verify the Savings tab (testTag "Tab-savings") is selected Swipe right across the Savings QR; verify the USDT tab (testTag "Tab-usdt") is selected and wait until the USDT QR is visible Swipe left across the USDT QR; verify the Savings tab is selected - Swipe left across the Savings QR in 600 ms (`adb shell input swipe 860 1176 220 1176 600`); verify the Spending tab (testTag "Tab-spending") is selected - Swipe left across the Spending content in 600 ms; verify the USDT tab is selected and wait until its QR is visible + Swipe left across the Savings QR in 1200 ms (`adb shell input swipe 900 1176 150 1176 1200`); verify the Spending tab (testTag "Tab-spending") is selected + Swipe left across the Spending content in 1200 ms; verify the USDT tab is selected and wait until its QR is visible Swipe left from the top right of the USDT QR to above the sheet (`adb shell input swipe 950 720 100 200 300`); verify the Receive sheet is still open and the Savings tab is selected Swipe right from the top left of the Savings QR to above the sheet (`adb shell input swipe 100 720 950 200 300`); verify the Receive sheet is still open and the USDT tab is selected Swipe left across the USDT QR, then tap the Savings QR once; verify the "copied" tooltip appears From 8488077d862846e6da32aaff124cb8abd3667bcb Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 20 Oct 2026 11:25:51 +0200 Subject: [PATCH 4/7] fix: start the receive wrap from usdt after a usdt tab tap --- .../bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt b/app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt index 061a195748..4c87238ad9 100644 --- a/app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveQrScreen.kt @@ -392,7 +392,12 @@ fun ReceiveQrScreen( selectedTab = tab showDetails = false scope.launch { - lazyListState.animateScrollToItem(newIndex) + // USDT replaces the pager at once; land it on the USDT page so the next swipe starts there + if (tab == ReceiveTab.USDT) { + lazyListState.scrollToItem(newIndex) + } else { + lazyListState.animateScrollToItem(newIndex) + } } }, modifier = Modifier.padding(horizontal = 16.dp) From bdbb8b34d43a87f2fc439c5ad5a5a9d4e1382a82 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 20 Oct 2026 11:33:05 +0200 Subject: [PATCH 5/7] test: cover receive wrap after a usdt tab tap in journey --- journeys/receive/receive-tabs-wraparound.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/journeys/receive/receive-tabs-wraparound.xml b/journeys/receive/receive-tabs-wraparound.xml index 2c11995ccc..f0918b9ecf 100644 --- a/journeys/receive/receive-tabs-wraparound.xml +++ b/journeys/receive/receive-tabs-wraparound.xml @@ -21,6 +21,8 @@ Tap Receive (testTag "Receive") and verify the Savings tab (testTag "Tab-savings") is selected Swipe right across the Savings QR; verify the USDT tab (testTag "Tab-usdt") is selected and wait until the USDT QR is visible Swipe left across the USDT QR; verify the Savings tab is selected + Start a screen recording, tap the USDT tab (testTag "Tab-usdt") and wait until the USDT QR is visible, then swipe left across the USDT QR; verify the Savings tab is selected and the recording shows the USDT QR sliding straight on to the Savings QR, with no Auto or Spending QR and no second USDT screen in between + Start a screen recording, tap the USDT tab and wait until the USDT QR is visible, then tap the Savings tab; verify the Savings tab is selected and the recording shows the same single slide from USDT to Savings Swipe left across the Savings QR in 1200 ms (`adb shell input swipe 900 1176 150 1176 1200`); verify the Spending tab (testTag "Tab-spending") is selected Swipe left across the Spending content in 1200 ms; verify the USDT tab is selected and wait until its QR is visible Swipe left from the top right of the USDT QR to above the sheet (`adb shell input swipe 950 720 100 200 300`); verify the Receive sheet is still open and the Savings tab is selected From 14d81fa4ba497756597201a0567eb89f1268b990 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 20 Oct 2026 11:48:05 +0200 Subject: [PATCH 6/7] test: swipe the receive pager slowly in the above-sheet journey step --- journeys/receive/receive-tabs-wraparound.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/journeys/receive/receive-tabs-wraparound.xml b/journeys/receive/receive-tabs-wraparound.xml index f0918b9ecf..b0887eccbb 100644 --- a/journeys/receive/receive-tabs-wraparound.xml +++ b/journeys/receive/receive-tabs-wraparound.xml @@ -26,7 +26,7 @@ Swipe left across the Savings QR in 1200 ms (`adb shell input swipe 900 1176 150 1176 1200`); verify the Spending tab (testTag "Tab-spending") is selected Swipe left across the Spending content in 1200 ms; verify the USDT tab is selected and wait until its QR is visible Swipe left from the top right of the USDT QR to above the sheet (`adb shell input swipe 950 720 100 200 300`); verify the Receive sheet is still open and the Savings tab is selected - Swipe right from the top left of the Savings QR to above the sheet (`adb shell input swipe 100 720 950 200 300`); verify the Receive sheet is still open and the USDT tab is selected + Swipe right from the top left of the Savings QR to above the sheet (`adb shell input swipe 100 720 950 200 1200`); verify the Receive sheet is still open and the USDT tab is selected Swipe left across the USDT QR, then tap the Savings QR once; verify the "copied" tooltip appears Close Receive, turn USDT off (Settings, General, Payments), return to the wallet home screen and tap Receive; verify the Savings tab is selected and only Savings and Spending show Swipe right across the Savings QR; verify the Spending tab is selected From f71aeb8ad0ae53b5113439fc71b070256b98b616 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Tue, 20 Oct 2026 12:19:58 +0200 Subject: [PATCH 7/7] test: word the usdt exit check for both platforms in journey --- journeys/receive/receive-tabs-wraparound.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/journeys/receive/receive-tabs-wraparound.xml b/journeys/receive/receive-tabs-wraparound.xml index b0887eccbb..bd0a672eb5 100644 --- a/journeys/receive/receive-tabs-wraparound.xml +++ b/journeys/receive/receive-tabs-wraparound.xml @@ -21,8 +21,8 @@ Tap Receive (testTag "Receive") and verify the Savings tab (testTag "Tab-savings") is selected Swipe right across the Savings QR; verify the USDT tab (testTag "Tab-usdt") is selected and wait until the USDT QR is visible Swipe left across the USDT QR; verify the Savings tab is selected - Start a screen recording, tap the USDT tab (testTag "Tab-usdt") and wait until the USDT QR is visible, then swipe left across the USDT QR; verify the Savings tab is selected and the recording shows the USDT QR sliding straight on to the Savings QR, with no Auto or Spending QR and no second USDT screen in between - Start a screen recording, tap the USDT tab and wait until the USDT QR is visible, then tap the Savings tab; verify the Savings tab is selected and the recording shows the same single slide from USDT to Savings + Start a screen recording, tap the USDT tab (testTag "Tab-usdt") and wait until the USDT QR is visible, then swipe left across the USDT QR; verify the Savings tab is selected and the recording goes straight from the USDT QR to the Savings QR, with no Auto or Spending QR and no second USDT screen in between + Start a screen recording, tap the USDT tab and wait until the USDT QR is visible, then tap the Savings tab; verify the Savings tab is selected and the recording shows the same direct change from USDT to Savings Swipe left across the Savings QR in 1200 ms (`adb shell input swipe 900 1176 150 1176 1200`); verify the Spending tab (testTag "Tab-spending") is selected Swipe left across the Spending content in 1200 ms; verify the USDT tab is selected and wait until its QR is visible Swipe left from the top right of the USDT QR to above the sheet (`adb shell input swipe 950 720 100 200 300`); verify the Receive sheet is still open and the Savings tab is selected