Skip to content

fix: use one btc/usd denomination toggle - #1078

Merged
ovitrif merged 3 commits into
masterfrom
fix/single-denomination-toggle
Oct 26, 2026
Merged

ovitrif merged 3 commits into
masterfrom
fix/single-denomination-toggle

Conversation

@ben-kaufman

@ben-kaufman ben-kaufman commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Related to #974 (denomination selector portion).

Twin: synonymdev/bitkit-android#1654

This PR replaces the separate BTC and USD denomination buttons with one filled toggle that shows the current denomination in payment-request and subscription amount entry.

Description

  • Use the existing dark filled button with an orange BTC/USD label and swap icon; tapping converts the entered amount and updates the label through the existing rate-checked conversion path.
  • Keep a fixed BTC label without a swap icon when only Bitcoin denomination is allowed, and preserve the separate Bitcoin/fiat input-unit preference and accepted payment methods.

Out of Scope

Design

Request payment — enter amount, denomination decision in thread #1008. The control switches BTC/USD denomination; Savings is a separate balance choice.

Preview

Native screenshot pending.

QA Notes

Setup

Use the shared linked-wallet subscription setup (Android recipe at ae800aef, same Paykit transport prerequisites) and iOS journey backend setup. On this branch, configure a concrete simulator as described in AGENTS.md, then run:

E2E_BACKEND=network E2E_NETWORK=regtest xcodebuildmcp simulator build-and-run \
  --project-path Bitkit.xcodeproj --scheme Bitkit \
  --extra-args 'SWIFT_ACTIVE_COMPILATION_CONDITIONS=$(inherited) E2E_BUILD'

Use the repository-pinned packages and two saved contacts already linked as identities, with Paykit UI enabled. J1 requires USDT enabled and a fresh BTC/USD rate; its amount-entry checks need no funds. J2 requires USDT disabled with no USDT funds or pending transfers. Use the journey's comma-decimal locale for exact-cents checks. Existing Bitcoin regtest funds and a channel are needed only for the optional payment-method confirmation portion; close reviews without paying.

Journeys

  • J1: updated paykit-quoted-usdt.xml — one denomination control in request/subscription amount entry, exact USD restoration across repeated BTC/USD switches, and preserved review amounts.
  • J2: updated create-and-propose.xml — BTC-only subscriptions show a fixed BTC label with no swap icon, while the separate Bitcoin/fiat input-unit control remains usable.

Manual Tests

N/A

Automated Checks

  • ran documentation validation for the J1 follow-up: XML parsing, unchanged journey name/action count/identifiers, companion wording and local reference checks, and git diff --check. Existing amount-conversion test coverage is unchanged.

Evidence

At 9f34b932c4b0 on the final source: the all-target simulator build passed and the CI unit-test selection passed all 2,716 tests using XcodeBuildMCP and the configured Xcode 26.1 toolchain. SwiftFormat 0.64.0 full-repository lint reported 0/832 files needing formatting (50 skipped). Complete structured build/test diagnostics were inspected: no errors; five dSYM missing cached-module warnings reproduced identically with base source f1b84c33. AppIntents metadata extraction warnings also occur on the base. The initial diagnostic rebuild hit stale paths in the copied package cache; those local paths were repaired and both base and final builds then passed. The final source matches the unit-tested source byte for byte. The six integration-only test classes were excluded exactly as in the CI unit-test workflow.

Independent review of the final source, callers, journeys and changelog found no verified issues. Both updated journey XML files parse and git diff --check passes.

At 9f34b932c4b0, ovi-reviewer’s native QA reports the changed J1/J2 selector scenarios passing on two linked iOS 26.5 wallets with Xcode 27.0 and the pinned packages. Request/subscription BTC/USD round trips restored exact amounts through review/delivery; accepted-method round trips, empty/trailing-decimal input, BTC-only noninteractive denomination, separate input units and the 5,000-sat subscription proposal also passed. These are reviewer-reported results for the changed scenarios, not a full replay of either journey. No payment or subscription was signed.

The hosted E2E run on 9f34b932c4b0 failed LNURL @lnurl_1 in all three internal attempts: ReviewAmount-primary did not appear after 5 seconds. The first attempt passed the other 13 scenarios; later attempts retried only LNURL. Its failure screenshot shows a blank confirmation sheet. The LNURL confirm/send path, MoneyStack and AppViewModel are byte-identical to CI target f1b84c33; this PR changes only the payment-request/subscription amount editor. The underlying LNURL cause remains unconfirmed. That historical E2E run was not green; no manual rerun was queued for it.

At 4c95fd94d6aa, the documentation-only J1 follow-up corrects the Android Savings/Spending expectations in the iOS companion journey and README: valid quoted Bitcoin terms stay on confirmation with refreshed fees; unavailable/expired terms or a Lightning amount below its minimum return to Amount. Manual Amount then Back closes the sheet. The documented iOS exact-valid-terms distinction is preserved. XML/reference/whitespace checks and full SwiftFormat 0.64.0 lint passed (0/832 files requiring formatting, 50 skipped); fresh independent review found no verified issues. No application build or device journey was rerun for this documentation delta. The build, unit, device and E2E results above remain attributed to 9f34b932c4b0; the current-head CI results and additional reviewer device evidence follow below.

At 4c95fd94d6aa, ovi-reviewer’s additional device QA reports the remaining targeted J1 cases passing on two linked iOS 26.5 wallets with Xcode 27, German and comma-decimal input: Classic Bitcoin in both editors; long accepted-method labels at normal/accessibility-large text; six-decimal quoted and direct-USDT values; funded Savings/Spending switching with exact valid terms and refreshed fees; USDT-only contacts; retained incoming request cents; restricted accepted methods; and the subscription form with the software keyboard. Test 6 exercised invalid terms using a one-shot debugger hook returning false from Payment.isValid inside returnToAmountReviewIfNeeded; it was not a real-clock expiry test. Source and binary were unchanged, and no payment/subscription was signed. Earlier J1/J2 selector results remain attributed to 9f34b932c4b0. jvsena42’s code scan also has no findings; that review’s separate device gate is still pending.

At 4c95fd94d6aa, build, SwiftFormat, translation, unit and integration checks passed. The E2E run failed: attempt 1 passed 12/14 cases, with a Boost success-toast timeout and the LNURL msat ReviewAmount-primary timeout; Boost passed on attempt 2, while LNURL failed all three built-in attempts at lnurl.e2e.ts:352. The third attempt progressed farther through the msat fixtures before the same missing confirmation element. The exact CI merge 583875971a85 and its base ec2d68a5d18a have identical blobs for LNURL amount/confirm, SendSheet, AppViewModel, SheetViewModel, ScannerManager, MainNavView and MoneyStack. This matches the failure pattern tracked in #1087; the causal callback remains unconfirmed, and this is not a reproduction on an unchanged base build. No manual rerun or weakening of the check was performed.

At f77fab1081a7, piotr-iohk merged master f650cbb4, including the LNURL flow-state fixes. The five-file PR delta retains the same added/removed lines as the previously reviewed toggle and journey changes. Current-head build, SwiftFormat, translation, unit and integration checks pass. Hosted E2E now passes: LNURL and 12 other cases passed on the first attempt; the Lightning receive/send case initially timed out waiting for the 9,000-sat balance and passed on the workflow's built-in second attempt. The aggregate completed successfully on 2026-10-23. This worker started no manual retry. The prior LNURL failure is no longer observed in this run; historical failures above remain attributed to their original revisions.

At the same head, ovi-reviewer's device follow-up reports six targeted J1 cases passing on two linked iOS 26.5 wallets with Xcode 27 and comma-decimal input: long-note request review and Back navigation; exact incoming cents and six-decimal USDT quote preservation; direct USDT Send/Receive input; restricted accepted methods; funded valid/invalid Bitcoin terms; and USDT-only private contacts. Invalid terms again used a one-shot Payment.isValid debugger hook, not real-clock expiry. No payment or subscription was signed. Earlier selector/J2, Classic Bitcoin, long-label and keyboard evidence remains tied to its original revisions; this was not a full J1/J2 replay. piotr-iohk's current-head code reassessment also reports no actionable findings and performed no device tests. VoiceOver remains unverified; neither review is an approval.

Gaps

The author has not driven J1/J2 end to end on a prepared linked-wallet pair. Reviewer coverage is limited to the explicitly reported cases and revisions above; the invalid-terms test uses fault injection. Physical-device VoiceOver focus order and spoken updates remain unrun. The device reviewer could not load Figma for a pixel comparison; the separate code scan’s Figma observation is not a device pixel comparison. Native author screenshots and jvsena42’s separate device gate remain pending. No payments were made by this worker.

Models used

  • Planning/scoping: gpt-6.1-sol (reasoning: xhigh), gpt-6-astra (reasoning: xhigh)
  • Implementation: gpt-6.1-sol (reasoning: xhigh), gpt-6-astra (reasoning: xhigh)
  • Review: gpt-6-astra (reasoning: xhigh), gpt-6.1-sol (reasoning: high)
  • Review rounds: 3

@greptile-apps

greptile-apps Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge; no actionable issues were found.

Summary

Replaces the separate BTC and USD buttons with one filled denomination toggle in payment-request and subscription amount entry.

  • Payment requests and subscriptions switch BTC/USD with one amount control.

Reviews (1) · Last reviewed commit: "fix: use one btc/usd denomination toggle" · Reviewed by Greptile

@talosmachina talosmachina left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No findings. Replaces the per-asset ForEach of BTC and USD buttons with one NumberPadActionButton that shows the current denomination and converts to the next allowed asset. Reviewed 9f34b93, light tier.

What I checked, and 4 candidates I ruled out

Read in full: PaymentRequestAmountView in CreatePaymentRequestView.swift, NumberPadActionButton.swift, SubscriptionAmountView in CreateSubscriptionView.swift, both journey diffs.
Call sites traced: PaymentRequestAmountView (ReceiveSheet.swift with default prefix and assets, SubscriptionAmountView with prefix PaymentRequest and [.btc] when USDT is off).
CI: SwiftFormat, validate and Greptile green; Run Tests, Run Integration Tests and build-local were still pending at review time.
Not built here: iOS does not build on this side, so this was reasoned from the code and CI.

Ruled out

  • Removed <prefix>Asset-btc / <prefix>Asset-usd identifiers still referenced: nothing in BitkitTests, journeys/ or bitkit-e2e-tests main uses them.
  • Identifier mismatch with Android: both subscription and request flows use the PaymentRequest prefix, so the button is PaymentRequestDenominationToggle in both, matching the Android testTag and the shared journeys.
  • BTC-only subscription still switches: disabled: nextAsset == nil disables the button, and the action's guard let nextAsset is a second stop. No arrow-up-down image is passed, which is what J2 asserts.
  • Asset not in allowedAssets after load: .task still resets asset to allowedAssets.first, and Continue still checks allowedAssets.contains(asset), so the toggle cannot submit a disallowed denomination.

Merge confidence: 4/5, no test drives the toggle, and the unit and integration runs were still pending.

@piotr-iohk piotr-iohk left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QA review

Scope: Reviewed the full PR diff against its merge base, at 9f34b932.

No new actionable code findings.

Payment-request and subscription amount entry now use one filled control labeled with the current BTC or USD denomination. Tapping it converts through the existing rate-checked PaykitAmountEntryConversion path and updates the label. When USD is not allowed, the control is a fixed BTC label with no swap icon. The Bitcoin/fiat unit control and accepted payment methods stay in place. Spacing, alignment, and the Savings control on the linked amount frame remain in #974. The selector behavior and journey wording match bitkit-android#1654 at 60f04737. That comparison is limited to this flow.

Validation: This review did not run tests or a simulator. PaykitAmountEntryConversionTests already asserts exact repeated restores; it was inspected only. At this revision, SwiftFormat, integration tests, and the build-local job passed. The unit-test run was still in progress.

Ready for device testing.

Device testing: not performed in this review.

@ovi-reviewer ovi-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: 💬 Comment — selector scenarios pass; full journeys not replayed.

Findings: None.

QA for 9f34b93: Built the pinned source and packages with Xcode 27.0, then drove two linked iOS 26.5 wallets in a comma-decimal locale. These results cover the changed denomination scenarios in J1 and J2, rather than a complete replay of every existing branch in those journey files.

Test 1: J1 — request and subscription denomination toggle ✅ One filled toggle switches BTC/USD and restores exact source amounts through review and delivery.

Four request round trips restored 10,00 USD. 150,50 USD survived request review, recipient display, delivery and payer review; the subscription editor also restored 150,50 USD and delivered a USDT-only proposal. Accepted-method round trips restored 12,345 sats and 10,00 USD. Clearing disabled Continue, and trailing-decimal input 5, reviewed as 5,00 USD.

Mixed requests selected Savings when 250 USD exceeded the payer's 200 USDT, while retaining manual USDT selection; a covered 150 USD request selected USDT. No payment or subscription was signed.

Creator on the left, payer on the right; recordings play at 2×.

Amount entry and delivery Initial payment-method selection
j1-main.2x.mp4
j1-extra.2x.mp4
Test 2: J2 — BTC-only subscription ✅ BTC stays fixed without a swap icon, separate input units work, and the 5,000-sat proposal arrives unchanged.

With USDT disabled and no creator USDT funds, physically tapping the BTC control left it unchanged. The separate Bitcoin/USD input-unit button remained usable. Removing Savings disabled Choose Recipient; restoring it enabled the completed form. The long-description rejection appeared before sending, and shortening it allowed the monthly Journey Sub proposal to reach the payer as exactly 5,000 sats, payable through Savings only.

Creator on the left, payer on the right; recording plays at 2×.

j2.2x.mp4

Not driven: the optional funded Savings/Spending confirmation (no Bitcoin funds or usable channel); unchanged J1 branches for long translated labels on a narrow screen, Classic Bitcoin display, a USDT-only contact, and six-decimal/direct-USDT entry; software-keyboard layout and VoiceOver. The Figma frames were unavailable, so this does not claim a pixel comparison.

Twin: synonymdev/bitkit-android#1654 fix: use one btc/usd denomination toggle matches the control behavior and journey identifiers by source comparison.

Full review: f1b84c3..9f34b93, including both callers, conversion/error handling, accepted methods and updated journeys. The runtime change was exercised in both amount editors.

Reviewer model: gpt-6.1-sol
Reasoning effort: high


Reviewed by gpt-6.1-sol-high via gh-pr-review-loop skill
Commands: @ovi-reviewer review · test · retest

@ovitrif ovitrif added this to the 3.1.0 milestone Oct 21, 2026
@ovitrif

ovitrif commented Oct 21, 2026

Copy link
Copy Markdown
Collaborator

Milestone 3.1.0: this fixes the BTC/USD selector part of #974, which is on 3.1.0; the layout part stays tracked there.

@ovi-reviewer ovi-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: 💬 Comment — device cases pass; VoiceOver remains unverified.

Findings: None.

QA for 4c95fd9: I built the pinned source and packages with Xcode 27.0 and tested two linked iOS 26.5 wallets using German and a comma-decimal locale. No payment or subscription was signed. Videos play at 2×. Some retaken clips still have limited animation smoothness; the tested values and controls remain legible.

The earlier selector QA still applies: this delta changes only the companion journey and README, with no application or package changes. It proves repeated denomination/method switches, exact USD restoration through delivery, initial payment-method selection and the BTC-only subscription flow. The cases below extend that coverage.

Test 1: Classic Bitcoin in both amount editors ✅ Dot input and exactly 0.00123456 BTC survive review and reopening.

Both editors ran with de_DE and Classic Bitcoin display.

Subscription amount Request amount
j1-classic.2x.mp4
j1-classic-request.2x.mp4
Test 2: German accepted-method labels ✅ The labels wrap without clipping on a 402-point phone at normal and accessibility-large text.

The review retains 10,00 USD; the method chips wrap to additional rows.

j1-layout.2x.mp4

Test 3: Six-decimal USDT request ✅ Exactly 10,083396 USDT stays locked through quote loading and failure.

The delivered request is for 12,345 sats, accepting only USDT. The smaller BTC figure is the wallet-rate equivalent; no Bitcoin payment method is offered. Creator and delivered request values also matched in semantic UI snapshots.

j1-precision-payer.2x.mp4

Test 4: Direct USDT Send and Receive ✅ Comma entry preserves 5,5, and a failed Send quote retains 150,50.

The Send title is Betrag, matching the USDT request and contact flows. Both flows were closed without sending or sharing a deposit request.

j1-direct.2x.mp4

Test 5: Funded Savings/Spending confirmation ✅ Valid unchanged terms keep confirmation open with exactly 12,238 sats while the method and fee update.

A 10 USD request switches Savings → Spending → Savings without changing 0.00012238 BTC. Payment continues to require a swipe; none was performed.

j1-confirm-valid.2x.mp4

Test 6: Invalid quoted terms ✅ Switching methods returns to Amount with the exact request amount retained; Back closes the sheet.

This is a fault-injection check: a one-shot debugger hook returned false from Payment.isValid only during returnToAmountReviewIfNeeded. It exercises the invalid-terms branch, rather than waiting for a real clock expiry. The source and binary were unchanged.

j1-invalid.2x.mp4

Test 7: USDT-only private contact ✅ Only USDT is selectable; 0,01 and 5,5 remain exact with an unqualified available balance.

The German balance label is VERFÜGBAR, without a Spending qualifier. Amount, balance, USDT chip and Continue styling match direct USDT Send. Closed before review.

j1-contact.2x.mp4

Test 8: Preset request cents during quote failure ✅ The incoming 150,50 USD request retains both cents while preparing and after failure.

Covered USDT starts selected. Reopening the creator's amount editor also retained 150,50, checked by semantic UI snapshot.

j1-cents-review.2x.mp4

Test 9: Restricted accepted payment methods ✅ Savings and USDT work; Spending is disabled and switching back restores exactly 12,345 sats.

The locked USDT quote is 10,100803; Savings restores 0.00012345 BTC. Closed before review.

j1-rails.2x.mp4

Test 10: Subscription form with the software keyboard ✅ Name, Description and Choose Recipient stay reachable at normal and accessibility-large text.

The form scrolls above the keyboard while Choose Recipient remains pinned.

j2-keyboard.2x.mp4

Test 11: VoiceOver focus and speech ⏭️ Unrun on a physical device.

Semantic snapshots expose the denomination button's current BTC/USD label, but do not prove VoiceOver focus order or spoken updates. The available disposable test targets were headless simulators, so this remains a device accessibility check.

Figma was unavailable, so I do not claim a pixel comparison. I did not rerun the full unit/E2E suite locally for this documentation-only delta. Current-head unit tests and integration tests passed in CI; the current E2E run is still running. The earlier LNURL E2E failure remains unconfirmed.

Twin: synonymdev/bitkit-android#1654 fix: use one btc/usd denomination toggle matches the revised Android expectations by source comparison at 3d01e7de.

Delta review: 9f34b93..4c95fd9, plus the earlier QA gaps. Both reviewers found no actionable defects. XML parsing and whitespace checks pass. Android's confirmation behavior was checked in source; these device runs exercised iOS.

Reviewer model: gpt-6.1-sol
Reasoning effort: high


Reviewed by gpt-6.1-sol-high via gh-pr-review-loop skill
Commands: @ovi-reviewer review · test · retest

@jvsena42 jvsena42 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code scan: no findings.

Checked and clean:

  • One toggle now drives both the primary and secondary denomination. The amount the number pad holds is converted, never reinterpreted, when it flips. Checked against the merged Android twin synonymdev/bitkit-android#1654: same shape. Android also zeroes the button's debounce, which iOS doesn't need.
  • Figma (node 49107-130091): the dark filled pill with an orange "⇅ BTC" label and a leading icon matches the implementation.
  • No string keys changed; not performance-relevant.

Device gate (partial): 4c95fd9 — not run yet; pending paykit-quoted-usdt.xml (actions 2, 4-5, 16) and subscriptions/create-and-propose.xml (the toggle step), plus a screenshot against the frame. Device results will follow in a separate review.

@piotr-iohk piotr-iohk left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QA review

Scope: Full reassessment of the PR at f77fab10 after the comparison base moved from f1b84c3 to f650cbb4 and that base update touches journeys/paykit-quoted-usdt.xml. Inherited coverage is empty.

No new actionable code findings.

Payment-request and subscription amount entry use one filled control labeled with the current BTC or USD denomination. Tapping it converts through the existing rate-checked PaykitAmountEntryConversion path: an unchanged rate restores the entered amount, and a missing rate leaves the denomination in place and shows the rate-unavailable message. With USDT disabled, the control is a fixed BTC label with no swap icon. The Bitcoin/fiat unit control and accepted payment methods stay in place. The control, identifier PaymentRequestDenominationToggle, and shared journey actions match the denomination change on bitkit-android#1654 at 3d01e7de. The request amount frame shows one dark pill with an orange label and a leading swap icon. Savings placement remains in #974.

Validation: this review did not build the app or run tests. PaykitAmountEntryConversionTests was inspected and covers repeated toggles, edits, cleared input, and a failed rate. On this head, unit tests, integration tests, SwiftFormat, and build-local passed. Hosted E2E was still running. The Paykit Appium spec at bcf91fee drives contact payment and does not select this amount control.

Device testing: not performed in this review. Reviewer device notes on 9f34b932 and 4c95fd94 belong to those revisions. The amount view is unchanged since 4c95fd9.

Ready for device testing of J1 and J2. The hosted E2E result on this head was not available.

Reviewer model: grok-4.7
Reasoning effort: high

@ovi-reviewer ovi-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: 💬 Comment — device cases pass; VoiceOver remains unverified.

Findings: None.

QA for f77fab1: I built the pinned source and packages with Xcode 27.0 and tested two linked iOS 26.5 wallets in a comma-decimal locale. No payment or subscription was signed. Videos play at 2×; some simulator animations stutter, but the tested values and controls remain legible.

Test 1: J1 — long-note USDT request review ✅ Contact, Address and the wrapping invoice note scroll above Hide Details and the fee explanation; Swipe To Pay stays pinned.

The healthy fee review retained 150,50 USD. Back restored the exact amount, then closed the sheet. The paired recording shows delivery and review; the shorter clip shows the expanded details and Back navigation.

Delivery and review — creator left, payer right Details and Back
j1-delivery-pair.2x.mp4
j1-details.2x.mp4
Test 2: J1 — request precision after the merge ✅ The delivered 150,50 USD request retains its cents; a separate six-decimal USDT quote stays exact through quote failure.

The delivery recording above shows 150,50 USD through amount entry, fee review and Back. The USDT-only 12,345-sat request below retains exactly 10,108086 USDT while preparing and after the controlled quote failure. The smaller Bitcoin value is a wallet-rate equivalent; Bitcoin is not offered as a payment method.

Creator on the left, payer on the right.

j1-precision-pair.2x.mp4

Test 3: J1 — direct USDT Send and Receive ✅ Comma entry preserves 5,5 in both flows, and failed Send quoting retains exactly 150,50.

Both flows were closed without sending or sharing a deposit request.

Receive Send
j1-direct-receive.2x.mp4
j1-direct-send.2x.mp4
Test 4: J1 — restricted accepted payment methods ✅ Savings and USDT are available, Spending is disabled, and switching back restores exactly 12,345 sats.

USDT shows the locked 10,095001 quote. Closed before review.

j1-rails.2x.mp4

Test 5: J1 — funded valid and invalid Bitcoin terms ✅ Valid method switches keep confirmation open; invalid terms return to Amount with exactly 12,227 sats retained.

For a 10 USD request, Savings → Spending → Savings retains 12,227 sats; the fee changes from 143 sats to about 1 sat and back. The invalid-terms clip uses a one-shot debugger hook returning false from Payment.isValid only during returnToAmountReviewIfNeeded. This checks the invalidity branch rather than real clock expiry. Source and binary were unchanged. Back then closes the sheet.

Valid terms Injected invalid terms
j1-confirm-valid.2x.mp4
j1-confirm-invalid.2x.mp4
Test 6: J1 — USDT-only private contact ✅ Only USDT is selectable; 0,01 and 5,5 remain exact with an unqualified available balance.

Balance, asset control and keypad sit at the bottom above Continue, matching direct USDT Send. Closed before review.

j1-contact.2x.mp4

Test 7: VoiceOver focus and spoken denomination ⏭️ Unrun: no disposable physical device or simulator VoiceOver control was available.

I checked device inventory and the available simulator accessibility controls. Semantic snapshots do not prove VoiceOver focus order or spoken updates.

The earlier selector QA still covers repeated denomination/method switches, empty and trailing-decimal input, initial method selection and the BTC-only J2 proposal. The follow-up QA retains the Classic Bitcoin, German/large-label and software-keyboard cases. I checked that the selector, both callers and their amount-conversion/input helpers are unchanged at this head. These runs cover the affected scenarios, not a complete replay of J1 and J2.

Figma was unavailable, so I do not claim a pixel comparison. Current-head unit tests and integration tests passed in CI; hosted E2E is still running. I did not rerun the full unit/E2E suite locally.

Twin: synonymdev/bitkit-android#1654 fix: use one btc/usd denomination toggle matches the single control, allowed-denomination behavior and journey identifiers by source comparison at 3d01e7de; no Android device run was made here.

Delta review: 4c95fd9..f77fab1, including the merged-base integration around amount entry, request review and confirmation. Unrelated inherited allowance and LNURL changes were not driven by these device cases.

Reviewer model: gpt-6.1-sol
Reasoning effort: high


Reviewed by gpt-6.1-sol-high via gh-pr-review-loop skill
Commands: @ovi-reviewer review · test · retest

@ovitrif ovitrif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Device cases pass with no findings; VoiceOver isn't a blocker here.

@ovitrif
ovitrif merged commit 65d0ae3 into master Oct 26, 2026
20 checks passed
@ovitrif
ovitrif deleted the fix/single-denomination-toggle branch October 26, 2026 13:25
@ovitrif

ovitrif commented Oct 26, 2026

Copy link
Copy Markdown
Collaborator

@ben-kaufman Merged, as it was approved and green.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants