mirror of
https://github.com/SeedSigner/seedsigner.git
synced 2026-10-05 15:08:25 +00:00
Merge remote-tracking branch 'upstream/0_4_5' into qr_background_color
This commit is contained in:
@@ -6,6 +6,7 @@ persistent_settings = False
|
||||
[display]
|
||||
text_color = ORANGE
|
||||
qr_background_color = FFFFFF
|
||||
camera_rotation = 0
|
||||
|
||||
[wallet]
|
||||
network = main
|
||||
|
||||
+12
-27
@@ -10,6 +10,16 @@ from seedsigner.helpers import PiVideoStream, Singleton
|
||||
class Camera(Singleton):
|
||||
_video_stream = None
|
||||
_picamera = None
|
||||
_camera_rotation = None
|
||||
|
||||
@classmethod
|
||||
def get_instance(cls):
|
||||
# This is the only way to access the one and only Controller
|
||||
from seedsigner.models import Settings
|
||||
if cls._instance is None:
|
||||
cls._instance = cls.__new__(cls)
|
||||
cls._instance._camera_rotation = Settings.get_instance().camera_rotation
|
||||
return cls._instance
|
||||
|
||||
|
||||
def start_video_stream_mode(self, resolution=(512, 384), framerate=12, format="bgr"):
|
||||
@@ -28,7 +38,7 @@ class Camera(Singleton):
|
||||
return frame
|
||||
else:
|
||||
if frame is not None:
|
||||
return Image.fromarray(frame.astype('uint8'), 'RGB').rotate(90)
|
||||
return Image.fromarray(frame.astype('uint8'), 'RGB').rotate(90 + self._camera_rotation)
|
||||
return None
|
||||
|
||||
|
||||
@@ -59,37 +69,12 @@ class Camera(Singleton):
|
||||
self._picamera.awb_mode = 'off'
|
||||
self._picamera.awb_gains = g
|
||||
|
||||
"""
|
||||
When outputting to unencoded formats, the camera rounds the requested resolution.
|
||||
The horizontal resolution is rounded up to the nearest multiple of 32 pixels,
|
||||
while the vertical resolution is rounded up to the nearest multiple of 16 pixels.
|
||||
"""
|
||||
# resolution = self._picamera.resolution
|
||||
# if resolution.width % 32 == 0:
|
||||
# raw_width = resolution.width
|
||||
# else:
|
||||
# raw_width = resolution.width - (resolution.width % 32) + 32
|
||||
|
||||
# if resolution.height % 16 == 0:
|
||||
# raw_height = resolution.height
|
||||
# else:
|
||||
# raw_height = resolution.height + 16
|
||||
|
||||
# print(resolution)
|
||||
# print(raw_width, raw_height)
|
||||
# np_array = numpy.empty((raw_width, raw_height, 3), dtype=numpy.uint8)
|
||||
# self._picamera.capture(np_array, format='rgb')
|
||||
|
||||
# np_array.reshape((raw_width, raw_height, 3))
|
||||
|
||||
# return Image.fromarray(np_array[:resolution.width, :resolution.height, :].astype('uint8'), 'RGB')
|
||||
|
||||
stream = io.BytesIO()
|
||||
self._picamera.capture(stream, format='jpeg')
|
||||
|
||||
# "Rewind" the stream to the beginning so we can read its content
|
||||
stream.seek(0)
|
||||
return Image.open(stream)
|
||||
return Image.open(stream).rotate(90 + self._camera_rotation)
|
||||
|
||||
|
||||
def stop_single_frame_mode(self):
|
||||
|
||||
@@ -76,7 +76,8 @@ class Controller(Singleton):
|
||||
controller.settings_tools_view = SettingsToolsView()
|
||||
controller.screensaver = ScreensaverView(controller.buttons)
|
||||
|
||||
controller.screensaver_activation_ms = 60 * 1000
|
||||
controller.screensaver_activation_ms = 120 * 1000
|
||||
|
||||
|
||||
@property
|
||||
def camera(self):
|
||||
@@ -156,6 +157,8 @@ class Controller(Singleton):
|
||||
ret_val = self.show_qr_density_tool()
|
||||
elif ret_val == Path.PERSISTENT_SETTINGS:
|
||||
ret_val = self.show_persistent_settings_tool()
|
||||
elif ret_val == Path.CAMERA_ROTATION:
|
||||
ret_val = self.show_camera_rotation_tool()
|
||||
elif ret_val == Path.DONATE:
|
||||
ret_val = self.show_donate_tool()
|
||||
elif ret_val == Path.RESET:
|
||||
@@ -679,10 +682,13 @@ class Controller(Singleton):
|
||||
self.buttons.wait_for([B.KEY_RIGHT])
|
||||
|
||||
validate_network = NETWORKS[self.settings.network]
|
||||
validate_network_text = self.settings.network
|
||||
if "main" in address_type:
|
||||
validate_network = NETWORKS["main"]
|
||||
validate_network_text = "main"
|
||||
elif "test" in address_type:
|
||||
validate_network = NETWORKS["test"]
|
||||
validate_network_text = "test"
|
||||
|
||||
r = 0
|
||||
if address_type in ("Bech32-main", "Bech32-test") and len(address) == 62:
|
||||
@@ -779,7 +785,7 @@ class Controller(Singleton):
|
||||
derivation = self.settings_tools_view.draw_derivation_keyboard_entry(existing_derivation=self.settings.custom_derivation)
|
||||
self.settings.custom_derivation = derivation # save for next time
|
||||
else:
|
||||
derivation = Settings.calc_derivation(validate_network, "single sig", script_type)
|
||||
derivation = Settings.calc_derivation(validate_network_text, "single sig", script_type)
|
||||
|
||||
if derivation == "" or derivation == None:
|
||||
self.menu_view.draw_modal(["Invalid Derivation", "try again"], "", "Right to Continue")
|
||||
@@ -1074,6 +1080,13 @@ class Controller(Singleton):
|
||||
|
||||
### Show Donate Screen and QR
|
||||
|
||||
def show_camera_rotation_tool(self):
|
||||
r = self.settings_tools_view.display_camera_rotation()
|
||||
if r is not None:
|
||||
self.settings.camera_rotation = r
|
||||
|
||||
return Path.SETTINGS_SUB_MENU ### Show Donate Screen and QR
|
||||
|
||||
def show_donate_tool(self):
|
||||
self.settings_tools_view.display_donate_info_screen()
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from embit import bip39
|
||||
from embit.bip39 import mnemonic_to_bytes, mnemonic_from_bytes
|
||||
import unicodedata
|
||||
|
||||
import hashlib
|
||||
|
||||
|
||||
def calculate_checksum(partial_mnemonic: list, wordlist):
|
||||
@@ -28,8 +28,7 @@ def generate_mnemonic_from_bytes(entropy_bytes):
|
||||
|
||||
|
||||
def generate_mnemonic_from_dice(roll_data: str):
|
||||
entropyinteger = int(roll_data, 6)
|
||||
entropy_bytes = entropyinteger.to_bytes(32, byteorder="little")
|
||||
entropy_bytes = hashlib.sha256(roll_data.encode()).digest()
|
||||
|
||||
# Return as a list
|
||||
return bip39.mnemonic_from_bytes(entropy_bytes).split()
|
||||
|
||||
@@ -28,6 +28,7 @@ class Path:
|
||||
WALLET = 64
|
||||
QR_DENSITY_SETTING = 65
|
||||
PERSISTENT_SETTINGS = 67
|
||||
CAMERA_ROTATION = 69
|
||||
RESET = 68
|
||||
|
||||
# Seed Slots
|
||||
|
||||
@@ -13,7 +13,7 @@ class Settings(Singleton):
|
||||
if cls._instance:
|
||||
raise Exception("Instance already configured")
|
||||
|
||||
# Instantiate the one and only Controller instance
|
||||
# Instantiate the one and only instance
|
||||
settings = cls.__new__(cls)
|
||||
cls._instance = settings
|
||||
|
||||
@@ -27,7 +27,8 @@ class Settings(Singleton):
|
||||
},
|
||||
'display': {
|
||||
'text_color': "ORANGE",
|
||||
'qr_background_color': "FFFFFF"
|
||||
'qr_background_color': "FFFFFF",
|
||||
'camera_rotation': 0
|
||||
},
|
||||
'wallet': {
|
||||
'network': "main",
|
||||
@@ -50,6 +51,7 @@ class Settings(Singleton):
|
||||
self._data["system"]["debug"] = config.getboolean("system", "debug")
|
||||
self._data["system"]["default_language"] = config["system"]["default_language"]
|
||||
self._data["display"]["text_color"] = config["display"]["text_color"]
|
||||
self._data["display"]["camera_rotation"] = int(config["display"]["camera_rotation"])
|
||||
self.network = config["wallet"]["network"]
|
||||
self.software = config["wallet"]["software"]
|
||||
self.qr_density = int(config["wallet"]["qr_density"])
|
||||
@@ -136,6 +138,18 @@ class Settings(Singleton):
|
||||
self._data["display"]["qr_background_color"] = value
|
||||
self.__writeConfig()
|
||||
|
||||
@property
|
||||
def camera_rotation(self):
|
||||
return self._data["display"]["camera_rotation"]
|
||||
|
||||
@camera_rotation.setter
|
||||
def camera_rotation(self, value):
|
||||
if value in [0, 90, 180, 270]:
|
||||
self._data["display"]["camera_rotation"] = value
|
||||
self.__writeConfig()
|
||||
else:
|
||||
raise Exception("Unexpected display.camera_rotation settings.ini value")
|
||||
|
||||
### wallet
|
||||
|
||||
@property
|
||||
|
||||
@@ -124,7 +124,7 @@ class MenuView(View):
|
||||
### Settings Menu
|
||||
|
||||
def display_settings_menu(self) -> int:
|
||||
lines = ["... [ Return to Main ]", "Wallet: <wallet>", "Network: <network>", "QR Density: <density>", "Input / Output Tests", "Persistent Settings: <persistent>", "Version Info", "Donate to SeedSigner", "Reset SeedSigner"]
|
||||
lines = ["... [ Return to Main ]", "Wallet: <wallet>", "Network: <network>", "QR Density: <density>", "Input / Output Tests", "Persistent Settings: <persistent>", "Camera Rotation", "Version Info", "Donate to SeedSigner", "Reset SeedSigner"]
|
||||
input = 0
|
||||
|
||||
lines[1] = lines[1].replace("<wallet>", Settings.get_instance().software)
|
||||
@@ -157,10 +157,12 @@ class MenuView(View):
|
||||
elif self.selected_menu_num == 6:
|
||||
return Path.PERSISTENT_SETTINGS
|
||||
elif self.selected_menu_num == 7:
|
||||
return Path.VERSION_INFO
|
||||
return Path.CAMERA_ROTATION
|
||||
elif self.selected_menu_num == 8:
|
||||
return Path.DONATE
|
||||
return Path.VERSION_INFO
|
||||
elif self.selected_menu_num == 9:
|
||||
return Path.DONATE
|
||||
elif self.selected_menu_num == 10:
|
||||
return Path.RESET
|
||||
raise Exception("Unhandled case")
|
||||
|
||||
|
||||
@@ -1064,10 +1064,12 @@ class SeedToolsView(View):
|
||||
draw.rectangle((mask_width, 0, View.canvas_width - mask_width, pixels_per_block), fill=View.color)
|
||||
draw.rectangle((0, mask_height, pixels_per_block, View.canvas_height - mask_height), fill=View.color)
|
||||
|
||||
label_font = View.ROBOTOMONO24
|
||||
label_font = View.ASSISTANT26
|
||||
x_label = block_labels_x[cur_block_x]
|
||||
tw, th = draw.textsize(x_label, font=label_font)
|
||||
draw.text(((View.canvas_width - tw) / 2, (pixels_per_block - th) / 2), x_label, fill="BLACK", font=label_font)
|
||||
|
||||
# note: have to nudge the y-coord up (the extra "- 4") for some reason
|
||||
draw.text(((View.canvas_width - tw) / 2, ((pixels_per_block - th) / 2) - 4), x_label, fill="BLACK", font=label_font)
|
||||
|
||||
y_label = block_labels_y[cur_block_y]
|
||||
tw, th = draw.textsize(y_label, font=label_font)
|
||||
@@ -1209,8 +1211,6 @@ class SeedToolsView(View):
|
||||
display_version = autocontrast(
|
||||
seed_entropy_image,
|
||||
cutoff=2
|
||||
).rotate(
|
||||
90
|
||||
).crop(
|
||||
(120, 0, 600, 480)
|
||||
).resize(
|
||||
|
||||
@@ -79,6 +79,28 @@ class SettingsToolsView(View):
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def display_camera_rotation(self) -> int:
|
||||
lines = ["... [ Return to Settings ]"]
|
||||
lines.append("0 (default)")
|
||||
lines.append("90")
|
||||
lines.append("180")
|
||||
lines.append("270")
|
||||
|
||||
r = self.controller.menu_view.display_generic_selection_menu(lines, "Camera Rotation")
|
||||
if r == 1:
|
||||
return None
|
||||
elif r == 2:
|
||||
return 0
|
||||
elif r == 3:
|
||||
return 90
|
||||
elif r == 4:
|
||||
return 180
|
||||
elif r == 5:
|
||||
return 270
|
||||
else:
|
||||
return None
|
||||
|
||||
###
|
||||
### Version Info
|
||||
###
|
||||
|
||||
@@ -158,7 +158,7 @@ class View:
|
||||
text_overlay = Image.new("RGBA", (View.canvas_width, View.canvas_height), (255,255,255,0))
|
||||
text_overlay_draw = ImageDraw.Draw(text_overlay)
|
||||
if not font:
|
||||
font = View.COURIERNEW14
|
||||
font = View.ASSISTANT18
|
||||
tw, th = text_overlay_draw.textsize(text, font=font)
|
||||
if text_background:
|
||||
text_overlay_draw.rectangle(((240 - tw) / 2 - 3, 240 - th, (240 - tw) / 2 + tw + 3, 240), fill=text_background)
|
||||
|
||||
+2
-1
@@ -6,9 +6,10 @@ persistent_settings = False
|
||||
[display]
|
||||
text_color = ORANGE
|
||||
qr_background_color = FFFFFF
|
||||
camera_rotation = 180
|
||||
|
||||
[wallet]
|
||||
network = main
|
||||
software = Prompt
|
||||
qr_density = 2
|
||||
custom_derivation = m/0
|
||||
custom_derivation = m/0/0
|
||||
Reference in New Issue
Block a user