Skip to content

feat: add Stackbit 1248 vertical layout for backup display#847

Open
bitcoisas wants to merge 5 commits into
selfcustody:developfrom
bitcoisas:feat/stackbit-1248-vertical
Open

feat: add Stackbit 1248 vertical layout for backup display#847
bitcoisas wants to merge 5 commits into
selfcustody:developfrom
bitcoisas:feat/stackbit-1248-vertical

Conversation

@bitcoisas
Copy link
Copy Markdown

@bitcoisas bitcoisas commented Mar 31, 2026

What is this PR for?

This PR adds vertical layout support for Stackbit 1248 backup display.

Currently, the Stackbit 1248 grid only supports the horizontal layout (rows = digits, columns = weights 1/2/4/8). This adds a menu to choose between "Standard" (horizontal) and "Vertical" (rows = weights, columns = digits), which is essentially the transposition of the grid.

This PR covers the backup/display side only. The input/loading side will be addressed in a separate PR as discussed with maintainers.

Close backup part of #834

Changes made to:

  • Code
  • Tests
  • i18n
  • Docs
  • CHANGELOG

Did you build the code and tested on device?

  • Tested on simulator, not yet on device. Looking for feedback on the approach first.

What is the purpose of this pull request?

  • Bug fix
  • New feature
  • Docs update
  • Other

Screenshots (not the same words on the devices):

After selecting Stackbit 1248 on menu:

Stackbit 1248 menu - large screen Stackbit 1248 menu - small screen

Choosing Standard:

Standard layout - large screen Standard layout - small screen

Choosing Vertical:

Vertical layout - large screen Vertical layout - small screen

@bitcoisas bitcoisas changed the title Feat/stackbit 1248 vertical feat: add Stackbit 1248 vertical layout for backup display Mar 31, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 31, 2026

Codecov Report

❌ Patch coverage is 98.19277% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 97.32%. Comparing base (8c6579a) to head (22b4cb3).

Files with missing lines Patch % Lines
src/krux/pages/home_pages/mnemonic_backup.py 96.22% 2 Missing ⚠️
src/krux/pages/stack_1248.py 99.11% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop     #847      +/-   ##
===========================================
+ Coverage    97.31%   97.32%   +0.01%     
===========================================
  Files           83       83              
  Lines        10632    10798     +166     
===========================================
+ Hits         10346    10509     +163     
- Misses         286      289       +3     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@joaozinhom
Copy link
Copy Markdown

IMO this is ready to review

@bitcoisas bitcoisas marked this pull request as ready for review March 31, 2026 19:04
Copy link
Copy Markdown

@jaonoctus jaonoctus left a comment

Choose a reason for hiding this comment

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

utACK

Copy link
Copy Markdown
Member

@qlrd qlrd left a comment

Choose a reason for hiding this comment

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

cACK

IMO you can make 1 square per page. While in Amigo you have a big screen, users will already flip the metal backup. It's good for user review to confirm the dots. Also maybe its too smal for m5 to use more than 1 per page (in this geometry).

I think will be good refactor some lines so we can reuse them in both this and #839

Comment thread src/krux/pages/stack_1248.py Outdated
Comment on lines +349 to +379
n_word_cols = 2
n_cols_per_word = 4
word_col_gap = 4
row_gap = 3
header_h = FONT_HEIGHT

label_w = FONT_WIDTH
x_start = MINIMAL_PADDING
right_pad = MINIMAL_PADDING

available_w = (
self.ctx.display.width() - x_start - label_w - word_col_gap - right_pad
)
cell_w = available_w // (n_word_cols * n_cols_per_word)

n_rows = (len(words_list) + n_word_cols - 1) // n_word_cols
available_h = self.ctx.display.height() - y_start
cell_h = (available_h - n_rows * header_h - (n_rows - 1) * row_gap) // (
n_rows * 4
)
cell_h = min(cell_h, FONT_HEIGHT)

grid_w = n_cols_per_word * cell_w
row_total_h = header_h + 4 * cell_h

dot_size = max(min(cell_w, cell_h) - 6, 1)
radius = dot_size // 2

x_label = x_start
x_grid_left = x_label + label_w
x_grid_right = x_grid_left + grid_w + word_col_gap
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.

All those variables are necessary? IMO this could be simplified with constants.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

These variables are used for layout calculation on different screen sizes! Happy to simplify if you have specific suggestions :)

Copy link
Copy Markdown
Member

@qlrd qlrd Apr 4, 2026

Choose a reason for hiding this comment

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

My suggestion requires adding some constants at the beginning (untested):

N_WORD_COLS = 2 
WORD_COL_GAP = 4 # also matches `n_cols_per_word` in your commit
ROW_GAP = 3
Suggested change
n_word_cols = 2
n_cols_per_word = 4
word_col_gap = 4
row_gap = 3
header_h = FONT_HEIGHT
label_w = FONT_WIDTH
x_start = MINIMAL_PADDING
right_pad = MINIMAL_PADDING
available_w = (
self.ctx.display.width() - x_start - label_w - word_col_gap - right_pad
)
cell_w = available_w // (n_word_cols * n_cols_per_word)
n_rows = (len(words_list) + n_word_cols - 1) // n_word_cols
available_h = self.ctx.display.height() - y_start
cell_h = (available_h - n_rows * header_h - (n_rows - 1) * row_gap) // (
n_rows * 4
)
cell_h = min(cell_h, FONT_HEIGHT)
grid_w = n_cols_per_word * cell_w
row_total_h = header_h + 4 * cell_h
dot_size = max(min(cell_w, cell_h) - 6, 1)
radius = dot_size // 2
x_label = x_start
x_grid_left = x_label + label_w
x_grid_right = x_grid_left + grid_w + word_col_gap
available_w = (
self.ctx.display.width() - (MINIMAL_PADDING * 2) - FONT_WIDTH - WORD_COL_GAP
)
cell_w = available_w // (N_WORD_COLS * WORD_COL_GAP)
n_rows = (len(words_list) + N_WORD_COLS - 1) // N_WORD_COLS
available_h = self.ctx.display.height() - y_start
cell_h = (available_h - n_rows * FONT_HEIGHT - (n_rows - 1) * ROW_GAP) // (
n_rows * 4
)
cell_h = min(cell_h, FONT_HEIGHT)
grid_w = WORD_COL_GAP * cell_w
row_total_h = FONT_HEIGHT + 4 * cell_h
dot_size = max(min(cell_w, cell_h) - 6, 1)
radius = dot_size // 2
x_label = MINIMAL_PADDING
x_grid_left = x_label + FONT_WIDTH
x_grid_right = x_grid_left + grid_w + WORD_COL_GAP

Or something like that, is a suggestion, try yourself :)

Comment thread src/krux/pages/stack_1248.py
Comment thread src/krux/pages/stack_1248.py Outdated
Comment thread src/krux/pages/stack_1248.py
@qlrd
Copy link
Copy Markdown
Member

qlrd commented Apr 1, 2026

Also, you could do a more cleaner history:

pick 2b7e8df9
fixup e521f8d3 # or maybe squash, if you wanna

Copy link
Copy Markdown
Member

@qlrd qlrd left a comment

Choose a reason for hiding this comment

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

nits:

Comment thread src/krux/pages/home_pages/mnemonic_backup.py
Comment thread src/krux/pages/home_pages/mnemonic_backup.py
Comment thread tests/pages/test_stackbit.py Outdated
Comment thread tests/pages/test_stackbit.py Outdated
Comment thread tests/pages/test_stackbit.py Outdated
Comment thread tests/pages/test_stackbit.py
Comment thread tests/pages/test_stackbit.py Outdated
@qlrd qlrd mentioned this pull request Apr 1, 2026
4 tasks
Copy link
Copy Markdown

@joaozinhom joaozinhom left a comment

Choose a reason for hiding this comment

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

ACK ba4c588

qlrd added a commit to qlrd/krux that referenced this pull request Apr 2, 2026
This commit add a feature commented by @jaonoctus on a [\selfcustody#847
comment](https://github.com/selfcustody/krux/pull/847/changes#r3029819808),
where an unecessary review about multiple lines could be avoided
automatically if we apply the `mccabe` plugin to `pylint`. Tested with
some weird complex code and catch nice.
qlrd added a commit to qlrd/krux that referenced this pull request Apr 3, 2026
This commit add a feature commented by @jaonoctus on a [\selfcustody#847
comment](https://github.com/selfcustody/krux/pull/847/changes#r3029819808),
where an review about multiple lines review could be avoided
automatically if we apply the `mccabe` plugin to `pylint`.

E.g, visually complexity could lead humans to interpret some lines as
complex given a experience of how code should be or not to be; some
standars could say that 25 lines could be the limit of a readability.
But a cyclomatic complexity on a function could be used as a "how real
complex is the function" and "it should be really refactored?".

Tested with `max-complexity=13` and `max-complexity=20` in tags
`v26.03.0`, branches `main`, `develop` and
`feat/stackbit-1248-vertical`. For more details about values a wikipedia
short ref:

* 1–10: Simple procedure: `little risk`;
* 11–20: More complex: `moderate risk`;
* 21–50: Complex: `high risk`.
* > 50: Untestable code: `very high risk`;
qlrd added a commit to qlrd/krux that referenced this pull request Apr 3, 2026
This commit add a feature commented by @jaonoctus on a [\selfcustody#847
comment](https://github.com/selfcustody/krux/pull/847/changes#r3029819808),
where an review about multiple lines review could be avoided
automatically if we apply the `mccabe` plugin to `pylint`.

E.g, visually complexity could lead humans to interpret some lines as
complex given a experience of how code should be or not to be; some
standars could say that 25 lines could be the limit of a readability.
But a cyclomatic complexity on a function could be used as a "how real
complex is the function" and "it should be really refactored?".

Tested with `max-complexity=13` and `max-complexity=20` in tags
`v26.03.0`, branches `main`, `develop` and
`feat/stackbit-1248-vertical`. For more details about values a wikipedia
short ref:

* 1–10: Simple procedure: `little risk`;
* 11–20: More complex: `moderate risk`;
* 21–50: Complex: `high risk`.
* > 50: Untestable code: `very high risk`;
qlrd added a commit to qlrd/krux that referenced this pull request Apr 3, 2026
This commit add a feature commented by @jaonoctus on a [\selfcustody#847
comment](https://github.com/selfcustody/krux/pull/847/changes#r3029819808),
where an review about multiple lines review could be avoided
automatically if we apply the `mccabe` plugin to `pylint`.

E.g, visually complexity could lead humans to interpret some lines as
complex given a experience of how code should be or not to be; some
standars could say that 25 lines could be the limit of a readability.
But a cyclomatic complexity on a function could be used as a "how real
complex is the function" and "it should be really refactored?".

Tested with `max-complexity=13` and `max-complexity=20` in tags
`v26.03.0`, branches `main`, `develop` and
`feat/stackbit-1248-vertical`. For more details about values a wikipedia
short ref:

* 1–10: Simple procedure: `little risk`;
* 11–20: More complex: `moderate risk`;
* 21–50: Complex: `high risk`.
* > 50: Untestable code: `very high risk`;
@bitcoisas bitcoisas force-pushed the feat/stackbit-1248-vertical branch 2 times, most recently from 0d0e0ee to bd31de8 Compare April 3, 2026 22:09
qlrd added a commit to qlrd/krux that referenced this pull request Apr 4, 2026
This commit add a feature commented by @jaonoctus on a [\selfcustody#847
comment](https://github.com/selfcustody/krux/pull/847/changes#r3029819808),
where an review about multiple lines review could be avoided
automatically if we apply the `mccabe` plugin to `pylint`.

E.g, visually complexity could lead humans to interpret some lines as
complex given a experience of how code should be or not to be; some
standars could say that 25 lines could be the limit of a readability.
But a cyclomatic complexity on a function could be used as a "how real
complex is the function" and "it should be really refactored?".

Tested with `max-complexity=13` and `max-complexity=20` in tags
`v26.03.0`, branches `main`, `develop` and
`feat/stackbit-1248-vertical`. For more details about values a wikipedia
short ref:

* 1–10: Simple procedure: `little risk`;
* 11–20: More complex: `moderate risk`;
* 21–50: Complex: `high risk`.
* > 50: Untestable code: `very high risk`;

For now, this commit found 7 `too-complex` functions on source code
base.
qlrd added a commit to qlrd/krux that referenced this pull request Apr 4, 2026
This commit add a feature commented by @jaonoctus on a [\selfcustody#847
comment](https://github.com/selfcustody/krux/pull/847/changes#r3029819808),
where an review about multiple lines review could be avoided
automatically if we apply the `mccabe` plugin to `pylint`.

E.g, visually complexity could lead humans to interpret some lines as
complex given a experience of how code should be or not to be; some
standars could say that 25 lines could be the limit of a readability.
But a cyclomatic complexity on a function could be used as a "how real
complex is the function" and "it should be really refactored?".

Tested with `max-complexity=13` and `max-complexity=20` in tags
`v26.03.0`, branches `main`, `develop` and
`feat/stackbit-1248-vertical`. For more details about values a wikipedia
short ref:

* 1–10: Simple procedure: `little risk`;
* 11–20: More complex: `moderate risk`;
* 21–50: Complex: `high risk`.
* > 50: Untestable code: `very high risk`;

For now, this commit found 7 `too-complex` functions on source code
base.
Copy link
Copy Markdown
Member

@qlrd qlrd left a comment

Choose a reason for hiding this comment

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

LGTM. Just need a rebase

@bitcoisas bitcoisas force-pushed the feat/stackbit-1248-vertical branch 7 times, most recently from dd5174d to c09ce04 Compare April 16, 2026 03:53
@bitcoisas
Copy link
Copy Markdown
Author

LGTM. Just need a rebase

Did the rebase, but idk why the ci is blocking my commit name on "i18n"... Tried to tie everything here

@qlrd
Copy link
Copy Markdown
Member

qlrd commented Apr 16, 2026

LGTM. Just need a rebase

Did the rebase, but idk why the ci is blocking my commit name on "i18n"... Tried to tie everything here

you found a bug on wagoid/action-conventional-commit. I will try to fix this step.

While, you can reword c09ce04 to feat(i18n): ..., i believe.

@bitcoisas bitcoisas force-pushed the feat/stackbit-1248-vertical branch from c09ce04 to 8a3cc69 Compare April 16, 2026 15:25
@bitcoisas
Copy link
Copy Markdown
Author

LGTM. Just need a rebase

Did the rebase, but idk why the ci is blocking my commit name on "i18n"... Tried to tie everything here

you found a bug on wagoid/action-conventional-commit. I will try to fix this step.

While, you can reword c09ce04 to feat(i18n): ..., i believe.

We did it!!! Thanks! Everything check passed!

Copy link
Copy Markdown
Member

@odudex odudex left a comment

Choose a reason for hiding this comment

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

ACK
@jdlcdl what's your take regarding this feature inclusion?

@bitcoisas bitcoisas force-pushed the feat/stackbit-1248-vertical branch from 3d3a27e to 8a3cc69 Compare May 5, 2026 04:44
@bitcoisas
Copy link
Copy Markdown
Author

bitcoisas commented May 5, 2026

@odudex happy to share the video of this PR running on my yahboom :)

thx @joaozinhom for your help!

WhatsApp.Video.2026-05-05.at.16.42.38.mp4

Copy link
Copy Markdown
Member

@qlrd qlrd left a comment

Choose a reason for hiding this comment

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

ACK 8a3cc69

@odudex
Copy link
Copy Markdown
Member

odudex commented May 11, 2026

Ok, before merging, can you add a CHANGELOG entry and documentation with a screenshot of the vertical option (generated through simulator/sequences script update)?

@bitcoisas
Copy link
Copy Markdown
Author

@odudex Done! Added CHANGELOG entry, documentation with screenshots of Vertical layouts, also a tiny description, and updated the simulator sequences script to generate the new screenshots.

@bitcoisas bitcoisas force-pushed the feat/stackbit-1248-vertical branch from bccdab0 to 8b2881d Compare May 12, 2026 07:18
@bitcoisas bitcoisas force-pushed the feat/stackbit-1248-vertical branch from 8b2881d to 22b4cb3 Compare May 12, 2026 07:22
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