From 3227889b5fde75007b1d61360ab3c04b46df2fcb Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Mon, 19 Oct 2026 13:57:18 -0300 Subject: [PATCH 1/3] fix: swipe between receive tabs from the usdt qr Co-Authored-By: Claude Opus 5.5 --- Bitkit/Extensions/View+SwipeGestures.swift | 4 ++- Bitkit/Views/Wallets/UsdtReceiveView.swift | 1 + changelog.d/next/usdt-swipe.fixed.md | 1 + journeys/receive/usdt-receive-swipe-tabs.xml | 30 ++++++++++++++++++++ 4 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 changelog.d/next/usdt-swipe.fixed.md create mode 100644 journeys/receive/usdt-receive-swipe-tabs.xml diff --git a/Bitkit/Extensions/View+SwipeGestures.swift b/Bitkit/Extensions/View+SwipeGestures.swift index b713e9118..e31d8a382 100644 --- a/Bitkit/Extensions/View+SwipeGestures.swift +++ b/Bitkit/Extensions/View+SwipeGestures.swift @@ -14,8 +14,10 @@ extension View { // MARK: Segmented tab swipes /// Swipe left/right to move between adjacent tabs (same order as `T.allCases` / `SegmentedControl`). + /// Pass `tabs` when the control shows only some cases, in its display order. func swipeSegmentedTabs( selection: Binding, + tabs visibleTabs: [T]? = nil, minimumDragDistance: CGFloat = 20, swipeThreshold: CGFloat = 50, animation: Animation = .easeInOut(duration: 0.2) @@ -27,7 +29,7 @@ extension View { let verticalAmount = value.translation.height guard abs(horizontalAmount) > abs(verticalAmount) else { return } - let tabs = Array(T.allCases) + let tabs = visibleTabs ?? Array(T.allCases) guard let currentIndex = tabs.firstIndex(of: selection.wrappedValue) else { return } if horizontalAmount < -swipeThreshold, currentIndex < tabs.count - 1 { diff --git a/Bitkit/Views/Wallets/UsdtReceiveView.swift b/Bitkit/Views/Wallets/UsdtReceiveView.swift index b6e7d939a..5af5d3a6a 100644 --- a/Bitkit/Views/Wallets/UsdtReceiveView.swift +++ b/Bitkit/Views/Wallets/UsdtReceiveView.swift @@ -62,6 +62,7 @@ struct UsdtReceiveView: View { onEdit: { draftAmount = amount; page = .amount }, onNetwork: { page = .networks } ) + .swipeSegmentedTabs(selection: Binding(get: { .usdt }, set: onSelectTab), tabs: tabs.map(\.tab)) case .networks: networkList case .amount: diff --git a/changelog.d/next/usdt-swipe.fixed.md b/changelog.d/next/usdt-swipe.fixed.md new file mode 100644 index 000000000..9b98106fd --- /dev/null +++ b/changelog.d/next/usdt-swipe.fixed.md @@ -0,0 +1 @@ +Swiping over the USDT receive QR now moves to the previous tab. diff --git a/journeys/receive/usdt-receive-swipe-tabs.xml b/journeys/receive/usdt-receive-swipe-tabs.xml new file mode 100644 index 000000000..593b8a3d2 --- /dev/null +++ b/journeys/receive/usdt-receive-swipe-tabs.xml @@ -0,0 +1,30 @@ + + + On the Receive sheet, swiping sideways over the QR changes tabs on every tab, USDT included. + With USDT selected, a swipe to the right over its QR selects the tab before it (Spending) and + does not copy the address; a swipe to the left does nothing, since USDT is the last tab. A single + tap on the USDT QR still copies the address and shows the "copied" tooltip. + + Precondition: onboarded dev wallet with USDT enabled (introductory sheet or Settings, General, + Payments), no CJIT invoice pending, start on the wallet home screen. The USDT address loads + without funding; wait for the QR before swiping. + + The copy shows as a tooltip over the QR for about two seconds, so a check for "no copy" reads a + screenshot taken right after the swipe. Swipe with AXe (`axe swipe --start-x 80 --start-y 420 + --end-x 320 --end-y 420 --duration 0.3 --udid ` on a 390 pt wide simulator) across the + middle of the QR, about 60% of its width. On a wallet without a Lightning channel, Spending shows + its setup view instead of a QR. + + iOS: the return from Spending to USDT goes through the paged `TabView`, which moves on a 300 ms + swipe as well; the 600 ms in that step is kept so the two platforms run the same action. + + + Tap Receive (id "Receive") + Tap the USDT tab (id "Tab-usdt") and wait until the USDT QR is visible + Swipe right across the QR and take a screenshot right away + Verify the Spending tab (id "Tab-spending") is selected, the Lightning receive content or the Spending setup is shown, and the screenshot shows no "copied" tooltip + Swipe left across the middle of the Spending content, whether it shows a Lightning QR or the Spending setup, in 600 ms (`axe swipe --start-x 320 --start-y 420 --end-x 80 --end-y 420 --duration 0.6`); verify the USDT tab is selected and wait until its QR is visible + Swipe left across the USDT QR and take a screenshot right away; verify the USDT tab stays selected and the screenshot shows no "copied" tooltip + Tap the USDT QR once and verify the "copied" tooltip appears + + From ea5252dc02244e29d63880533d328b24e690bb41 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Mon, 19 Oct 2026 14:30:56 -0300 Subject: [PATCH 2/3] chore: rename changelog fragment Co-Authored-By: Claude Opus 5.5 --- changelog.d/next/{usdt-swipe.fixed.md => 1020.fixed.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename changelog.d/next/{usdt-swipe.fixed.md => 1020.fixed.md} (100%) diff --git a/changelog.d/next/usdt-swipe.fixed.md b/changelog.d/next/1020.fixed.md similarity index 100% rename from changelog.d/next/usdt-swipe.fixed.md rename to changelog.d/next/1020.fixed.md From 047370c1e351f2be432d844e2576cff02bff53dc Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Mon, 19 Oct 2026 17:32:41 -0300 Subject: [PATCH 3/3] fix: let receive sheet swipe down from the usdt qr Co-Authored-By: Claude Opus 5.5 --- Bitkit/Extensions/View+SwipeGestures.swift | 46 ++++++++++++---------- Bitkit/Views/Wallets/UsdtReceiveView.swift | 2 +- 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/Bitkit/Extensions/View+SwipeGestures.swift b/Bitkit/Extensions/View+SwipeGestures.swift index e31d8a382..46ec555a2 100644 --- a/Bitkit/Extensions/View+SwipeGestures.swift +++ b/Bitkit/Extensions/View+SwipeGestures.swift @@ -15,34 +15,40 @@ extension View { /// Swipe left/right to move between adjacent tabs (same order as `T.allCases` / `SegmentedControl`). /// Pass `tabs` when the control shows only some cases, in its display order. + /// Pass `simultaneous` inside a sheet, so a vertical drag still reaches the sheet's swipe-to-dismiss. + @ViewBuilder func swipeSegmentedTabs( selection: Binding, tabs visibleTabs: [T]? = nil, minimumDragDistance: CGFloat = 20, swipeThreshold: CGFloat = 50, - animation: Animation = .easeInOut(duration: 0.2) + animation: Animation = .easeInOut(duration: 0.2), + simultaneous: Bool = false ) -> some View { - highPriorityGesture( - DragGesture(minimumDistance: minimumDragDistance, coordinateSpace: .local) - .onEnded { value in - let horizontalAmount = value.translation.width - let verticalAmount = value.translation.height - guard abs(horizontalAmount) > abs(verticalAmount) else { return } - - let tabs = visibleTabs ?? Array(T.allCases) - guard let currentIndex = tabs.firstIndex(of: selection.wrappedValue) else { return } - - if horizontalAmount < -swipeThreshold, currentIndex < tabs.count - 1 { - withAnimation(animation) { - selection.wrappedValue = tabs[currentIndex + 1] - } - } else if horizontalAmount > swipeThreshold, currentIndex > 0 { - withAnimation(animation) { - selection.wrappedValue = tabs[currentIndex - 1] - } + let drag = DragGesture(minimumDistance: minimumDragDistance, coordinateSpace: .local) + .onEnded { value in + let horizontalAmount = value.translation.width + let verticalAmount = value.translation.height + guard abs(horizontalAmount) > abs(verticalAmount) else { return } + + let tabs = visibleTabs ?? Array(T.allCases) + guard let currentIndex = tabs.firstIndex(of: selection.wrappedValue) else { return } + + if horizontalAmount < -swipeThreshold, currentIndex < tabs.count - 1 { + withAnimation(animation) { + selection.wrappedValue = tabs[currentIndex + 1] + } + } else if horizontalAmount > swipeThreshold, currentIndex > 0 { + withAnimation(animation) { + selection.wrappedValue = tabs[currentIndex - 1] } } - ) + } + if simultaneous { + simultaneousGesture(drag) + } else { + highPriorityGesture(drag) + } } } diff --git a/Bitkit/Views/Wallets/UsdtReceiveView.swift b/Bitkit/Views/Wallets/UsdtReceiveView.swift index 5af5d3a6a..ae157cd6d 100644 --- a/Bitkit/Views/Wallets/UsdtReceiveView.swift +++ b/Bitkit/Views/Wallets/UsdtReceiveView.swift @@ -62,7 +62,7 @@ struct UsdtReceiveView: View { onEdit: { draftAmount = amount; page = .amount }, onNetwork: { page = .networks } ) - .swipeSegmentedTabs(selection: Binding(get: { .usdt }, set: onSelectTab), tabs: tabs.map(\.tab)) + .swipeSegmentedTabs(selection: Binding(get: { .usdt }, set: onSelectTab), tabs: tabs.map(\.tab), simultaneous: true) case .networks: networkList case .amount: