diff --git a/seedsigner-screenshots b/seedsigner-screenshots index 584157c1..facec05b 160000 --- a/seedsigner-screenshots +++ b/seedsigner-screenshots @@ -1 +1 @@ -Subproject commit 584157c13180f60ebe113a7b0679f7346c93e9eb +Subproject commit facec05bcaf74b551d0746d7a6c868defb5302ca diff --git a/src/seedsigner/controller.py b/src/seedsigner/controller.py index 3ff20e2f..a963e13f 100644 --- a/src/seedsigner/controller.py +++ b/src/seedsigner/controller.py @@ -238,10 +238,10 @@ class Controller(Singleton): used. Only used by the test suite. """ from seedsigner.views import MainMenuView, BackStackView - from seedsigner.views.screensaver import OpeningSplashScreen + from seedsigner.views.screensaver import OpeningSplashView from seedsigner.gui.toast import RemoveSDCardToastManagerThread - OpeningSplashScreen().start() + OpeningSplashView().run() """ Class references can be stored as variables in python! diff --git a/src/seedsigner/views/screensaver.py b/src/seedsigner/views/screensaver.py index 55c5cde0..6ff6eedb 100644 --- a/src/seedsigner/views/screensaver.py +++ b/src/seedsigner/views/screensaver.py @@ -3,16 +3,19 @@ import os import random import time +from dataclasses import dataclass from gettext import gettext as _ from seedsigner.gui.components import Fonts, GUIConstants, load_image from seedsigner.gui.screens.screen import BaseScreen from seedsigner.models.settings import Settings from seedsigner.models.settings_definition import SettingsConstants +from seedsigner.views.view import View logger = logging.getLogger(__name__) + # TODO: This early code is now outdated vis-a-vis Screen vs View distinctions class LogoScreen(BaseScreen): def __init__(self): @@ -29,45 +32,78 @@ class LogoScreen(BaseScreen): self.partner_logos[partner] = load_image(logo_url) + def _run(self): + pass + + def get_random_partner(self) -> str: return self.partners[random.randrange(len(self.partners))] +@dataclass +class OpeningSplashView(View): + is_screenshot_renderer: bool = False + force_partner_logos: bool|None = None + + def run(self): + self.run_screen( + OpeningSplashScreen, + is_screenshot_renderer=self.is_screenshot_renderer, + force_partner_logos=self.force_partner_logos + ) + + + class OpeningSplashScreen(LogoScreen): - def start(self): + def __init__(self, is_screenshot_renderer=False, force_partner_logos=None): + self.is_screenshot_renderer = is_screenshot_renderer + self.force_partner_logos = force_partner_logos + super().__init__() + + + def _render(self): from PIL import Image from seedsigner.controller import Controller controller = Controller.get_instance() show_partner_logos = Settings.get_instance().get_value(SettingsConstants.SETTING__PARTNER_LOGOS) == SettingsConstants.OPTION__ENABLED + if self.force_partner_logos is not None: + show_partner_logos = self.force_partner_logos if show_partner_logos: logo_offset_y = -56 else: logo_offset_y = 0 - # Fade in alpha - for i in range(250, -1, -25): - self.logo.putalpha(255 - i) - background = Image.new("RGBA", size=self.logo.size, color="black") - self.renderer.canvas.paste(Image.alpha_composite(background, self.logo), (0, logo_offset_y)) - self.renderer.show_image() + background = Image.new("RGBA", size=self.logo.size, color="black") + if not self.is_screenshot_renderer: + # Fade in alpha + for i in range(250, -1, -25): + self.logo.putalpha(255 - i) + self.renderer.canvas.paste(Image.alpha_composite(background, self.logo), (0, logo_offset_y)) + self.renderer.show_image() + else: + # Skip animation for the screenshot generator + self.renderer.canvas.paste(self.logo, (0, logo_offset_y)) # Display version num below SeedSigner logo font = Fonts.get_font(GUIConstants.get_body_font_name(), GUIConstants.get_top_nav_title_font_size()) version = f"v{controller.VERSION}" - (left, top, version_tw, version_th) = font.getbbox(version, anchor="lt") # The logo png is 240x240, but the actual logo is 70px tall, vertically centered + logo_height = 70 version_x = int(self.renderer.canvas_width/2) - version_y = int(self.canvas_height/2) + 35 + logo_offset_y + GUIConstants.COMPONENT_PADDING + version_y = int(self.canvas_height/2) + int(logo_height/2) + logo_offset_y + GUIConstants.COMPONENT_PADDING self.renderer.draw.text(xy=(version_x, version_y), text=version, font=font, fill=GUIConstants.ACCENT_COLOR, anchor="mt") - self.renderer.show_image() + + if not self.is_screenshot_renderer: + self.renderer.show_image() if show_partner_logos: - # Hold on the version num for a moment - time.sleep(1) + if not self.is_screenshot_renderer: + # Hold on the version num for a moment + time.sleep(1) # Set up the partner logo partner_logo: Image.Image = self.partner_logos[self.get_random_partner()] @@ -89,7 +125,9 @@ class OpeningSplashScreen(LogoScreen): self.renderer.show_image() - time.sleep(2) + if not self.is_screenshot_renderer: + # Hold on the splash screen for a moment + time.sleep(2) diff --git a/src/seedsigner/views/seed_views.py b/src/seedsigner/views/seed_views.py index 2026d51b..4c6e0347 100644 --- a/src/seedsigner/views/seed_views.py +++ b/src/seedsigner/views/seed_views.py @@ -1250,7 +1250,11 @@ class SeedWordsBackupTestPromptView(View): class SeedWordsBackupTestView(View): - def __init__(self, seed_num: int, bip85_data: dict = None, confirmed_list: list[bool] = None, cur_index: int = None): + def __init__(self, seed_num: int, bip85_data: dict = None, confirmed_list: list[bool] = None, cur_index: int = None, rand_seed: int = None): + """ + Note: `rand_seed` is ONLY USED BY THE SCREENSHOT GENERATOR!!! (to ensure + consistent screenshot results). + """ super().__init__() self.seed_num = seed_num if self.seed_num is None: @@ -1269,11 +1273,15 @@ class SeedWordsBackupTestView(View): self.confirmed_list = [] self.cur_index = cur_index + self.rand_seed = rand_seed def run(self): from embit import bip39 + if self.rand_seed is not None: + random.seed(self.rand_seed + self.cur_index if self.cur_index is not None else 0) + if self.cur_index is None: self.cur_index = int(random.random() * len(self.mnemonic_list)) while self.cur_index in self.confirmed_list: diff --git a/tests/screenshot_generator/generator.py b/tests/screenshot_generator/generator.py index e07381da..fdd3acbb 100644 --- a/tests/screenshot_generator/generator.py +++ b/tests/screenshot_generator/generator.py @@ -15,7 +15,7 @@ from embit.script import Script # These must precede any SeedSigner imports. sys.modules['seedsigner.hardware.ST7789'] = MagicMock() sys.modules['seedsigner.gui.screens.screensaver'] = MagicMock() -sys.modules['seedsigner.views.screensaver'] = MagicMock() +sys.modules['seedsigner.views.screensaver.ScreensaverScreen'] = MagicMock() sys.modules['RPi'] = MagicMock() sys.modules['RPi.GPIO'] = MagicMock() sys.modules['seedsigner.hardware.camera'] = MagicMock() @@ -34,6 +34,7 @@ from seedsigner.models.settings import Settings from seedsigner.models.settings_definition import SettingsConstants, SettingsDefinition from seedsigner.views import (MainMenuView, PowerOptionsView, RestartView, NotYetImplementedView, UnhandledExceptionView, psbt_views, seed_views, settings_views, tools_views) +from seedsigner.views.screensaver import OpeningSplashView from seedsigner.views.view import ErrorView, NetworkMismatchErrorView, OptionDisabledView, PowerOffView, View from .utils import ScreenshotComplete, ScreenshotRenderer @@ -189,6 +190,8 @@ def generate_screenshots(locale): screenshot_sections = { "Main Menu Views": [ + (OpeningSplashView, dict(is_screenshot_renderer=True, force_partner_logos=True)), + (OpeningSplashView, dict(is_screenshot_renderer=True, force_partner_logos=False), "OpeningSplashView_no_partner_logos"), MainMenuView, (MainMenuView, {}, 'MainMenuView_SDCardStateChangeToast_removed', SDCardStateChangeToastManagerThread(action=MicroSD.ACTION__REMOVED)), (MainMenuView, {}, 'MainMenuView_SDCardStateChangeToast_inserted', SDCardStateChangeToastManagerThread(action=MicroSD.ACTION__INSERTED)), @@ -223,8 +226,8 @@ def generate_screenshots(locale): (seed_views.SeedBIP85SelectChildIndexView, dict(seed_num=0, num_words=24)), (seed_views.SeedBIP85InvalidChildIndexView, dict(seed_num=0, num_words=12)), (seed_views.SeedWordsBackupTestPromptView, dict(seed_num=0)), - (seed_views.SeedWordsBackupTestView, dict(seed_num=0)), - (seed_views.SeedWordsBackupTestMistakeView, dict(seed_num=0, cur_index=7, wrong_word="unlucky")), + (seed_views.SeedWordsBackupTestView, dict(seed_num=0, rand_seed=6102)), + (seed_views.SeedWordsBackupTestMistakeView, dict(seed_num=0, cur_index=7, wrong_word="satoshi")), (seed_views.SeedWordsBackupTestSuccessView, dict(seed_num=0)), (seed_views.SeedTranscribeSeedQRFormatView, dict(seed_num=0)), (seed_views.SeedTranscribeSeedQRWarningView, dict(seed_num=0)), @@ -389,6 +392,7 @@ def generate_screenshots(locale): locale_readme += f"""""" for screenshot in screenshot_list: if type(screenshot) == tuple: + toast_thread = None if len(screenshot) == 2: view_cls, view_args = screenshot view_name = view_cls.__name__