diff --git a/src/krux/display.py b/src/krux/display.py index 9d87e2f8..de014b67 100644 --- a/src/krux/display.py +++ b/src/krux/display.py @@ -50,7 +50,7 @@ FLASH_MSG_TIME = 2000 -SMALLEST_WIDTH = 135 +NARROW_SCREEN_WITH = 135 SMALLEST_HEIGHT = 240 # Splash will use horizontally-centered text plots. Uses Thin spaces to help with alignment @@ -243,7 +243,9 @@ def to_lines(self, text, max_lines=None): lines = [] start = 0 line_count = 0 - columns = self.usable_width() if self.width() > SMALLEST_WIDTH else self.width() + columns = ( + self.usable_width() if self.width() > NARROW_SCREEN_WITH else self.width() + ) if Settings().i18n.locale in ["ko-KR", "zh-CN"] and lcd.string_has_wide_glyph( text ): @@ -369,7 +371,9 @@ def draw_hcentered_text( if info_box: bg_color = theme.info_bg_color padding = ( - DEFAULT_PADDING if self.width() > SMALLEST_WIDTH else MINIMAL_PADDING + DEFAULT_PADDING + if self.width() > NARROW_SCREEN_WITH + else MINIMAL_PADDING ) self.fill_rectangle( padding - 3, diff --git a/src/krux/pages/__init__.py b/src/krux/pages/__init__.py index 86e08db8..d9b77528 100644 --- a/src/krux/pages/__init__.py +++ b/src/krux/pages/__init__.py @@ -42,7 +42,7 @@ FLASH_MSG_TIME, FONT_HEIGHT, FONT_WIDTH, - SMALLEST_WIDTH, + NARROW_SCREEN_WITH, STATUS_BAR_HEIGHT, ) from ..qr import to_qr_codes @@ -253,7 +253,6 @@ def display_qr_codes(self, data, qr_format, title=""): time.sleep_ms(self.ctx.input.debounce_value) self.ctx.input.reset_ios_state() extra_debounce_flag = False - continue btn = self.ctx.input.wait_for_button(num_parts == 1) if btn in TOGGLE_BRIGHTNESS: if qr_foreground == WHITE: @@ -701,7 +700,7 @@ def draw_battery_indicator(self): def draw_wallet_indicator(self): """Draws wallet fingerprint or BIP85 child at top if wallet is loaded""" if self.ctx.is_logged_in(): - if self.ctx.display.width() > SMALLEST_WIDTH: + if self.ctx.display.width() > NARROW_SCREEN_WITH: self.ctx.display.draw_hcentered_text( self.ctx.wallet.key.fingerprint_hex_str(True), STATUS_BAR_HEIGHT - FONT_HEIGHT - 1, @@ -720,7 +719,7 @@ def draw_wallet_indicator(self): def draw_network_indicator(self): """Draws test at top if testnet is enabled""" if self.ctx.is_logged_in() and self.ctx.wallet.key.network["name"] == "Testnet": - if self.ctx.display.width() > SMALLEST_WIDTH: + if self.ctx.display.width() > NARROW_SCREEN_WITH: self.ctx.display.draw_string( 12, STATUS_BAR_HEIGHT - FONT_HEIGHT - 1, diff --git a/src/krux/pages/mnemonic_editor.py b/src/krux/pages/mnemonic_editor.py index da8ba7df..098649d5 100644 --- a/src/krux/pages/mnemonic_editor.py +++ b/src/krux/pages/mnemonic_editor.py @@ -20,11 +20,10 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -import board from embit import bip39 from embit.wordlists.bip39 import WORDLIST from . import Page, ESC_KEY, LETTERS, proceed_menu -from ..display import DEFAULT_PADDING, MINIMAL_PADDING, FONT_HEIGHT +from ..display import DEFAULT_PADDING, MINIMAL_PADDING, FONT_HEIGHT, NARROW_SCREEN_WITH from ..krux_settings import t from ..themes import theme from ..input import BUTTON_TOUCH, BUTTON_ENTER, BUTTON_PAGE, BUTTON_PAGE_PREV @@ -49,7 +48,7 @@ def __init__(self, ctx, mnemonic=None, new=False): self.mnemonic_length = len(self.current_mnemonic) self.header_offset = DEFAULT_PADDING self.search_ranges = {} - self.narrow_screen = board.config["type"] == "m5stickv" + self.narrow_screen = self.ctx.display.width() <= NARROW_SCREEN_WITH def compute_search_ranges(self, alt_wordlist=None): """Compute search ranges for the autocomplete and possible_letters functions""" diff --git a/src/krux/pages/qr_view.py b/src/krux/pages/qr_view.py index cc33175a..18b957f1 100644 --- a/src/krux/pages/qr_view.py +++ b/src/krux/pages/qr_view.py @@ -27,7 +27,7 @@ from ..krux_settings import t from ..settings import THIN_SPACE from ..qr import get_size -from ..display import DEFAULT_PADDING, FONT_HEIGHT, SMALLEST_WIDTH +from ..display import DEFAULT_PADDING, FONT_HEIGHT, NARROW_SCREEN_WITH from ..input import ( BUTTON_ENTER, BUTTON_PAGE, @@ -148,8 +148,8 @@ def _region_legend(self, row, column): def draw_grided_qr(self, mode): """Draws grided QR""" self.ctx.display.clear() - if self.ctx.display.width() > SMALLEST_WIDTH: - grid_size = self.ctx.display.width() // SMALLEST_WIDTH + if self.ctx.display.width() > NARROW_SCREEN_WITH: + grid_size = self.ctx.display.width() // NARROW_SCREEN_WITH else: grid_size = 1 grid_offset = self.ctx.display.width() % (self.qr_size + 2) diff --git a/src/krux/pages/stack_1248.py b/src/krux/pages/stack_1248.py index f034d236..a27226ff 100644 --- a/src/krux/pages/stack_1248.py +++ b/src/krux/pages/stack_1248.py @@ -24,7 +24,7 @@ from . import Page from ..themes import theme from ..krux_settings import t -from ..display import DEFAULT_PADDING, FONT_HEIGHT, FONT_WIDTH, SMALLEST_WIDTH +from ..display import DEFAULT_PADDING, FONT_HEIGHT, FONT_WIDTH, NARROW_SCREEN_WITH from ..input import ( BUTTON_ENTER, BUTTON_PAGE, @@ -215,7 +215,7 @@ def export_1248(self, word_index, y_offset, word): self.x_offset = DEFAULT_PADDING # case for m5stickv - if self.ctx.display.width() < SMALLEST_WIDTH: + if self.ctx.display.width() < NARROW_SCREEN_WITH: self.x_offset = 5 self.x_pad = 2 * FONT_WIDTH self.y_offset = 2 * FONT_HEIGHT @@ -226,7 +226,7 @@ def export_1248(self, word_index, y_offset, word): self._draw_labels(y_offset, word_index) digits, digits_str = self._word_to_digits(word) self._draw_punched(digits, y_offset) - if self.ctx.display.height() > SMALLEST_WIDTH: + if self.ctx.display.height() > NARROW_SCREEN_WITH: self.ctx.display.draw_string( self.x_offset + 17 * FONT_WIDTH, y_offset, @@ -393,7 +393,7 @@ def index(self, index, btn): def enter_1248(self): """UI to manually enter a Stackbit 1248""" - if self.ctx.display.width() > SMALLEST_WIDTH: + if self.ctx.display.width() > NARROW_SCREEN_WITH: self.x_pad = 3 * FONT_WIDTH else: self.x_pad = 2 * FONT_WIDTH diff --git a/src/krux/pages/tiny_seed.py b/src/krux/pages/tiny_seed.py index 078c4d10..982e5e24 100644 --- a/src/krux/pages/tiny_seed.py +++ b/src/krux/pages/tiny_seed.py @@ -37,7 +37,7 @@ MINIMAL_DISPLAY, FONT_HEIGHT, FONT_WIDTH, - SMALLEST_WIDTH, + NARROW_SCREEN_WITH, SMALLEST_HEIGHT, ) from ..camera import OV7740_ID, OV2640_ID, OV5642_ID @@ -62,7 +62,7 @@ def __init__(self, ctx, label="Tiny Seed"): self.label = label self.x_offset = MINIMAL_PADDING + 2 * FONT_WIDTH self.printer = None - if self.ctx.display.width() > SMALLEST_WIDTH: + if self.ctx.display.width() > NARROW_SCREEN_WITH: self.x_pad = self.ctx.display.width() * 2 // 27 self.y_pad = self.ctx.display.height() // 17 else: diff --git a/tests/pages/test_page.py b/tests/pages/test_page.py index 7f08a635..8626079d 100644 --- a/tests/pages/test_page.py +++ b/tests/pages/test_page.py @@ -1,5 +1,11 @@ import pytest from ..shared_mocks import mock_context +from . import create_ctx + +TEST_QR_DATA = "test" +TEST_QR_DATA_IMAGE = bytearray( + b"\x7f\xd3?H\nvU\xdd\xae\xa4\xdbut\x83\x80\xe0_\xf5\x070\x00O%7\x97\xd2\xd6\xd1\xe7\xc6\x1ae\xe5\xb2\x00J\xd5\x1f\xd9\t\xd23]N\xbckdu\xb5\x94\xa0\xaf\xf9\xb7\t\x00" +) @pytest.fixture @@ -88,3 +94,64 @@ def test_prompt_amigo(mocker, amigo, mock_page_cls): ctx.input.touch = mocker.MagicMock(current_index=mocker.MagicMock(side_effect=[0])) ctx.input.wait_for_button = mocker.MagicMock(side_effect=[BUTTON_TOUCH]) assert page.prompt("test prompt") == False + + +def test_display_qr_code(mocker, m5stickv, mock_page_cls): + from krux.input import BUTTON_ENTER + from krux.qr import FORMAT_NONE + + ctx = create_ctx(mocker, [BUTTON_ENTER]) + page = mock_page_cls(ctx) + + # Test QR code display + page.display_qr_codes(TEST_QR_DATA, FORMAT_NONE) + + assert ctx.input.wait_for_button.call_count == 1 + assert ctx.display.draw_qr_code.call_count == 1 + assert ctx.display.draw_qr_code.call_args == mocker.call(0, TEST_QR_DATA_IMAGE) + + +def test_display_qr_code_light_theme(mocker, m5stickv, mock_page_cls): + from krux.input import BUTTON_ENTER + from krux.qr import FORMAT_NONE + from krux.themes import theme, WHITE + + ctx = create_ctx(mocker, [BUTTON_ENTER]) + page = mock_page_cls(ctx) + + # Mock light theme background color + theme.bg_color = WHITE + # Test QR code display + page.display_qr_codes(TEST_QR_DATA, FORMAT_NONE) + + assert ctx.input.wait_for_button.call_count == 1 + assert ctx.display.draw_qr_code.call_count == 1 + assert ctx.display.draw_qr_code.call_args == mocker.call( + 0, TEST_QR_DATA_IMAGE, light_color=WHITE + ) + + +def test_display_qr_code_loop_through_brightness(mocker, m5stickv, mock_page_cls): + from krux.input import BUTTON_ENTER, BUTTON_PAGE + from krux.qr import FORMAT_NONE + from krux.themes import WHITE, DARKGREY + + BTN_SEQUENCE = [ + *([BUTTON_PAGE] * 3), # Loop through brightness + BUTTON_ENTER, # Exit + ] + + ctx = create_ctx(mocker, BTN_SEQUENCE) + page = mock_page_cls(ctx) + + # Test QR code display + page.display_qr_codes(TEST_QR_DATA, FORMAT_NONE) + + assert ctx.input.wait_for_button.call_count == len(BTN_SEQUENCE) + assert ctx.display.draw_qr_code.call_count == len(BTN_SEQUENCE) + assert ctx.display.draw_qr_code.call_args_list == [ + mocker.call(0, TEST_QR_DATA_IMAGE), # Default + mocker.call(0, TEST_QR_DATA_IMAGE, light_color=WHITE), # Brighter + mocker.call(0, TEST_QR_DATA_IMAGE, light_color=DARKGREY), # Darker + mocker.call(0, TEST_QR_DATA_IMAGE), # Default + ] diff --git a/tests/pages/test_qr_view.py b/tests/pages/test_qr_view.py index 1aa53496..289c1805 100644 --- a/tests/pages/test_qr_view.py +++ b/tests/pages/test_qr_view.py @@ -112,6 +112,39 @@ def test_loop_through_regions(amigo, mocker): assert ctx.display.draw_qr_code.call_count == 57 +def test_loop_through_brightness(amigo, mocker): + from krux.pages.qr_view import SeedQRView + from krux.themes import WHITE, DARKGREY + from krux.input import BUTTON_TOUCH + from krux.wallet import Wallet + + TOUCH_SEQ = [ + # Open touch menu + 1, # Toggle brightness to bright + # Open touch menu + 1, # Toggle brightness to dark + # Open touch menu + 1, # Toggle brightness to default + # Open touch menu + 4, # Exit + ] + + BTN_SEQUENCE = [BUTTON_TOUCH] * 8 + + ctx = create_ctx(mocker, BTN_SEQUENCE, touch_seq=TOUCH_SEQ) + data = TEST_DATA + seed_qr_view = SeedQRView(ctx, data=data, title=TEST_TITLE) + seed_qr_view.display_qr() + assert ctx.input.wait_for_button.call_count == len(BTN_SEQUENCE) + assert ctx.display.draw_qr_code.call_count == 4 + assert ctx.display.draw_qr_code.call_args_list == [ + mocker.call(0, TEST_CODE_BINARY_QR), # Default + mocker.call(0, TEST_CODE_BINARY_QR, light_color=WHITE), # Brighter + mocker.call(0, TEST_CODE_BINARY_QR, light_color=DARKGREY), # Darker + mocker.call(0, TEST_CODE_BINARY_QR), # Default + ] + + def test_add_frame(amigo, mocker): from krux.pages.qr_view import SeedQRView