Conversation
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Regtest APKDownload bitkit-dev-debug universal APK (expires in 30 days). |
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
jvsena42
left a comment
There was a problem hiding this comment.
Approved — no HIGH/MEDIUM findings at head 39373f24c. (Posted as a comment because GitHub does not allow approving your own PR.)
Checked: Traced the fit path end to end against Compose 1.12.0 sources (foundation LayoutUtils.finalMaxWidth, ui-text TextMeasurer/AndroidParagraph, material3 Text). On the fits=true path WordItem renders the word with softWrap=false, maxLines=1, overflow=Visible and weight(1f) (MnemonicWordsGrid.kt:226-235); with softWrap=false Compose gives the paragraph width max(ceil(maxIntrinsicWidth), minWidth), so a word is never broken or dropped, and a measurement mismatch could only overflow visibly into the 32dp column gap, never truncate. The measurement in rememberWordFontFit uses the same TextStyle (BodyMSB.copy(fontSize)), the same LocalDensity (font scale included) and the same font resolver as the rendered Text; material3 Text does not merge LocalTextStyle when a style is passed, InterFontFamily is a blocking resource font, so measured widths equal laid-out widths. Budget arithmetic is conservative: (gridWidth - gap)/2 floors while Row weight distribution gives each column floor or ceil, and per-number label widths are measured for 1..24 so two-digit labels in 24-word grids reduce the budget of the right words. On the fits=false fallback (font scale 2.0 or narrower) softWrap=true with maxLines=MAX and overflow=Visible keeps every character inside its column across lines, identical to master's behaviour, and the parent Box clip in ShowMnemonicScreen/RecoveryMnemonicScreen sits 32dp outside the grid. BoxWithConstraints always sees bounded width in both callers (verticalScroll Column, no IntrinsicSize ancestors), remember keys cover words, width and density, and both callers (backup sheet and recovery screen) go through the shared grid.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
jvsena42
left a comment
There was a problem hiding this comment.
Approved — no blocking HIGH/MEDIUM findings at head 535f6c022. (Posted as a comment because GitHub does not allow approving your own PR.)
Inline: MEDIUM (journey, non-blocking) — Journey runs on whatever phrase the wallet has, so it can pass with the bug reverted; LOW (journey, non-blocking) — Label-position checks cannot see a wrap in words 6 and 12 at head
Checked: Round 3 (535f6c0, new journey): Reviewed the round-3 delta: the new journeys/backup/show-mnemonic-long-words.xml and the two journeys/README.md rows. Every testTag the journey names exists at head: HeaderMenu (HomeScreen.kt:1402), DrawerSettings (DrawerMenu.kt:311), Tab-security (CustomTabRowWithSpacing.kt:58 via SettingsTab.Security), BackupWallet (SettingsScreen.kt:419), backup_mnemonic_words_box, SeedContainer and TapToReveal (ShowMnemonicScreen.kt:165/178/189). The flow order matches the code: BackupWalletClick opens Sheet.Backup, whose default route is BackupRoute.ShowMnemonic (SheetHost.kt:81), so the reveal screen is the first screen of the sheet. The visible texts "Back up your wallet" and "Tap To Reveal" match strings.xml, and the FLAG_SECURE note and the SeedContainer content-description warning match ShowMnemonicScreen.kt. No bitkit-ios twin exists, and the skip is recorded in the cross-platform table.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
jvsena42
left a comment
There was a problem hiding this comment.
Approved — no blocking HIGH/MEDIUM findings at head 24117c6e4. (Posted as a comment because GitHub does not allow approving your own PR.)
Inline: LOW — Proceed Without Backup is not shown on the first restore failure
Checked: Round 4 (24117c6): both earlier journey findings are fixed. Round 4 (24117c6): both earlier journey findings are fixed. The journey now wipes to.bitkit.dev and restores the fixed phrase abstract awesome category mushroom mosquito document multiply mechanic marriage mountain awesome mushroom. I recomputed its BIP39 checksum against the English wordlist (checksum bits 1110 = 1110), so it restores. Every slot except 2 and 11 holds an 8-letter word, including 10 and 12, and the description labels it a public test vector for the dev flavor and regtest only, never to be funded. The restore steps follow MainActivity's startup graph (Terms -> Intro skip -> Slides(LAST_SLIDE_INDEX) -> WarningMultipleDevices -> Restore), and every tag they name exists at head: Check1/Check2/Continue (TermsOfUseScreen.kt:91/99/109), SkipIntro (IntroScreen.kt:92), RestoreWallet (CreateWalletScreen.kt:90), MultipleDevices-button (WarningMultipleDevicesScreen.kt:70), Word-$index (RestoreWalletScreen.kt:416), RestoreButton (:301), GetStartedButton (WalletRestoreSuccessView.kt:59). The new height check is sound. In WordItem (MnemonicWordsGrid.kt:218-240) the label is BodyMSB at full size with maxLines=1. The word uses the same style at a size of 17sp or less, so one line is never taller than the label and any wrap is, in every slot including 6 and 12.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
jvsena42
left a comment
There was a problem hiding this comment.
Approved — no blocking HIGH/MEDIUM findings at head d2149c174. (Posted as a comment because GitHub does not allow approving your own PR.)
Checked: Follow-up: Reviewed d2149c1 only. The fallback now matches the restore error flow: WalletRestoreErrorView renders only when the node is ErrorStarting (ContentView.kt:405-407), ProceedWithoutBackupButton shows only when retryCount > 1 (WalletRestoreErrorView.kt:78-84), and onRestoreRetry advances Initial -> Retry(1) -> Retry(2) via countRetry() (WalletViewModel.kt:263-264, 622), so two failed Try Again taps are needed before Proceed appears. TryAgainButton (WalletRestoreErrorView.kt:75) and the confirm tag DialogConfirm (AppAlertDialog.kt:79) exist at head, and the dialog's confirm invokes onProceedWithoutRestore, which settles the restore state and lands on the wallet.
|
@jvsena42 e2e red + conflicts |
|
Approved, thanks. Both points: Conflicts: the shared e2e: Context on the churn is in #1275 (comment) — including the option of pulling the README rows out of every PR into one follow-up, if the team would rather stop the re-merges. |
…c-words # Conflicts: # journeys/README.md
# Conflicts: # journeys/README.md
# Conflicts: # journeys/README.md
There was a problem hiding this comment.
Verdict: ✅ Approve
Reaudit: diff 1 file.
Findings:
N/A
Audit:
Already done in comment.
QA: emu-1 Pixel 10 Pro emulator on Android 16
-
✅ passed: At 1.3 scale, all 12 words stayed single-line with uniform row spacing.
-
✅ passed: Reveal preserved card height at 1.3; all 12 pairs matched default sizing at 1.0.
-
✅ passed: At 2.0 scale, wide words wrapped within their columns without clipping.
-
✅ passed: Recovery Mnemonic rendered all 12 aligned pairs inside the grid.
Tip
Test 1 worth a journey:
- Clear app data and restore the fixed public test wallet
- Set system font scale to 1.3
- Go to Settings → Security → Back up your wallet
- Tap Tap To Reveal
- Verify all 12 words stay on one line and rows remain evenly spaced
- Return and reset system font scale to 1.0
Test 2 worth a journey:
- Set system font scale to 1.3
- Go to Settings → Security → Back up your wallet
- Record the hidden recovery phrase card bounds
- Tap Tap To Reveal and verify the card bounds stay unchanged
- Return and set system font scale to 1.0
- Open Back up your wallet and tap Tap To Reveal
- Verify all words and number labels render at the same default size
Test 3 worth a journey:
- Set system font scale to 2.0
- Go to Settings → Security → Back up your wallet
- Tap Tap To Reveal
- Scroll the recovery phrase sheet until all rows are exposed
- Verify wide words wrap inside their own column without clipping
- Return and reset system font scale to 1.0
Test 4 worth a journey:
- Open the Recovery screen
- Tap Show Seed Phrase
- Verify Recovery Mnemonic shows 12 aligned words inside the phrase grid
- Press back to return to Recovery
Coverage:
QA: 5 of 5 manual tests passed
Reviewed by gpt-5.6-sol-high via gh-pr-review-loop skill
Commands: @ovi-reviewer review · test · retest · audit (author or owner)




Fixes #633
Related to #1275
This PR fits long recovery phrase words on one line in the mnemonic grid instead of breaking them mid-word.
Description
mushroomormountainnext to the two-digit labels no longer wrap at larger font scales.Out of Scope
MnemonicWordsGrid.kt: no shrinking below 12sp; at extreme font scales words still wrap inside their column.MnemonicWordsGrid.kt: no Compose UI instrumented test for the composable wiring; sizing logic is covered by unit tests and was checked on device.MnemonicWordsGrid.kt: font size measurement runs during composition; not optimised for the worst case (24 words at large font scales).bitkit-ioswraps long mnemonic words at larger text sizes; not addressed here.Design
The design only shows short words at the default font scale. At font scale 1.0 the build matches it.
Preview
The screen sets
FLAG_SECURE, so these captures come from temporary uncommitted builds with screenshot blocking removed and BIP39 test words (abstract awesome category mushroom mosquito document multiply mechanic marriage mountain awesome mushroom).Reveal transition at font scale 1.3, no layout jump:
after-fs1.3-reveal.mp4
QA Notes
Manual Tests
regression:System font scale 1.0 → Show Mnemonic → reveal: words render at the default size, matching the design.regression:Recovery → Recovery Mnemonic: phrase grid renders correctly.The steps of test 1 were run on a Pixel 9 emulator with
journeys/backup/show-mnemonic-long-words.xml, committed in this PR and listed injourneys/README.md. The journey restores a fixed public BIP39 test phrase first, so the long words it checks are guaranteed to be there rather than left to whatever phrase the device happens to hold, and it wipes the app to do so — run it on a throwaway emulator. Its contents are inlined below.show-mnemonic-long-words.xml
Automated Checks
MnemonicWordsGridTest.kt.just compile,just test(2608 passed),just lint.