mirror of
https://github.com/SeedSigner/seedsigner.git
synced 2026-10-06 15:38:25 +00:00
Settings now json; Xpub export flow skipping screens based on Settings
This commit is contained in:
@@ -1,14 +0,0 @@
|
||||
[system]
|
||||
debug = False
|
||||
default_language = en
|
||||
persistent_settings = False
|
||||
|
||||
[display]
|
||||
text_color = ORANGE
|
||||
camera_rotation = 0
|
||||
|
||||
[wallet]
|
||||
network = main
|
||||
software = Prompt
|
||||
qr_density = 2
|
||||
custom_derivation = m/
|
||||
-12
@@ -1,17 +1,5 @@
|
||||
import configparser
|
||||
import sys
|
||||
import time
|
||||
|
||||
from seedsigner.controller import Controller
|
||||
|
||||
|
||||
config = configparser.ConfigParser()
|
||||
config.read("settings.ini")
|
||||
|
||||
# One-time setup to intialize the one and only Controller
|
||||
# TODO: Refactor how deep the ConfigParser needs to be passed around.
|
||||
Controller.configure_instance(config)
|
||||
|
||||
# Get the one and only Controller instance and start our main loop
|
||||
controller = Controller.get_instance()
|
||||
controller.start()
|
||||
|
||||
@@ -11,11 +11,11 @@ from subprocess import call
|
||||
from threading import Thread
|
||||
|
||||
from .models import (EncodeQRDensity, QRType, Seed, SeedStorage, Settings,
|
||||
ConfigurableSingleton, DecodeQR, DecodeQRStatus, EncodeQR, PSBTParser)
|
||||
Singleton, DecodeQR, DecodeQRStatus, EncodeQR, PSBTParser)
|
||||
|
||||
|
||||
|
||||
class Controller(ConfigurableSingleton):
|
||||
class Controller(Singleton):
|
||||
"""
|
||||
The Controller is a globally available singleton that maintains SeedSigner state.
|
||||
|
||||
@@ -34,50 +34,49 @@ class Controller(ConfigurableSingleton):
|
||||
"""
|
||||
VERSION = "0.5.0"
|
||||
|
||||
|
||||
@classmethod
|
||||
def configure_instance(cls, config=None):
|
||||
def get_instance(cls):
|
||||
from .gui import Renderer
|
||||
from .helpers import Buttons
|
||||
from .views import ScreensaverView
|
||||
# This is the only way to access the one and only instance
|
||||
if cls._instance is None:
|
||||
# Instantiate the one and only Controller instance
|
||||
controller = cls.__new__(cls)
|
||||
cls._instance = controller
|
||||
|
||||
super().configure_instance(config)
|
||||
# Input Buttons
|
||||
controller.buttons = Buttons.get_instance()
|
||||
|
||||
# Instantiate the one and only Controller instance
|
||||
controller = cls.__new__(cls)
|
||||
cls._instance = controller
|
||||
# models
|
||||
# TODO: Rename "storage" to something more indicative of its temp, in-memory state
|
||||
controller.storage = SeedStorage()
|
||||
controller.settings = Settings.get_instance()
|
||||
|
||||
# Input Buttons
|
||||
controller.buttons = Buttons.get_instance()
|
||||
# settings
|
||||
controller.DEBUG = controller.settings.debug
|
||||
controller.color = controller.settings.text_color
|
||||
|
||||
# models
|
||||
# TODO: Rename "storage" to something more indicative of its temp, in-memory state
|
||||
controller.storage = SeedStorage()
|
||||
Settings.configure_instance(config)
|
||||
controller.settings = Settings.get_instance()
|
||||
# Configure the Renderer
|
||||
Renderer.configure_instance({"text_color": controller.color})
|
||||
|
||||
# settings
|
||||
controller.DEBUG = controller.settings.debug
|
||||
controller.color = controller.settings.text_color
|
||||
# TODO: Refactor so that we don't need the Renderer here
|
||||
controller.renderer = Renderer.get_instance()
|
||||
|
||||
# Configure the Renderer
|
||||
Renderer.configure_instance({"text_color": controller.color})
|
||||
# Views
|
||||
# controller.menu_view = MenuView()
|
||||
# controller.seed_tools_view = SeedToolsView()
|
||||
# controller.io_test_view = IOTestView()
|
||||
# controller.signing_tools_view = SigningToolsView(controller.storage)
|
||||
# controller.settings_tools_view = SettingsToolsView()
|
||||
controller.screensaver = ScreensaverView(controller.buttons)
|
||||
|
||||
# TODO: Refactor so that we don't need the Renderer here
|
||||
controller.renderer = Renderer.get_instance()
|
||||
controller.back_stack = []
|
||||
|
||||
# Views
|
||||
# controller.menu_view = MenuView()
|
||||
# controller.seed_tools_view = SeedToolsView()
|
||||
# controller.io_test_view = IOTestView()
|
||||
# controller.signing_tools_view = SigningToolsView(controller.storage)
|
||||
# controller.settings_tools_view = SettingsToolsView()
|
||||
controller.screensaver = ScreensaverView(controller.buttons)
|
||||
|
||||
controller.back_stack = []
|
||||
|
||||
# Other behavior constants
|
||||
controller.screensaver_activation_ms = 120 * 1000
|
||||
# Other behavior constants
|
||||
controller.screensaver_activation_ms = 120 * 1000
|
||||
|
||||
return cls._instance
|
||||
|
||||
|
||||
@property
|
||||
@@ -147,6 +146,12 @@ class Controller(ConfigurableSingleton):
|
||||
next_destination = next_destination.run()
|
||||
|
||||
print(f"next_destination: {next_destination}")
|
||||
|
||||
if next_destination.skip_current_view:
|
||||
# Remove the current View from history; it's forwarding us straight
|
||||
# to the next View.
|
||||
self.pop_back_stack()
|
||||
|
||||
clear_history = next_destination.clear_history
|
||||
if next_destination.View_cls == BackStackView:
|
||||
# "Back" arrow was clicked; load the previous view
|
||||
|
||||
@@ -662,19 +662,21 @@ class SettingsQR:
|
||||
def add(self, segment, qr_type=QRType.SETTINGS):
|
||||
print(f"SettingsQR: {segment}")
|
||||
try:
|
||||
self.settings["features"] = {}
|
||||
self.settings = {}
|
||||
|
||||
# QR Settings format is space-separated key/value pairs
|
||||
for entry in segment.split(" "):
|
||||
key = entry.split("=")[0].strip()
|
||||
value = entry.split("=")[1].strip()
|
||||
self.settings["features"][key] = value
|
||||
self.settings[key] = value
|
||||
|
||||
# Remove values only needed for import
|
||||
self.settings["features"].pop("type", None)
|
||||
version = self.settings["features"].pop("version", None)
|
||||
self.settings.pop("type", None)
|
||||
version = self.settings.pop("version", None)
|
||||
if not version or int(version) != 1:
|
||||
raise Exception(f"Settings QR version {version} not supported")
|
||||
|
||||
self.config_name = self.settings["features"].pop("name", None)
|
||||
self.config_name = self.settings.pop("name", None)
|
||||
if self.config_name:
|
||||
self.config_name = self.config_name.replace("_", " ")
|
||||
|
||||
@@ -686,9 +688,8 @@ class SettingsQR:
|
||||
"2": SettingsConstants.OPTION__PROMPT,
|
||||
}
|
||||
map_abbreviated_sig_types = {
|
||||
"s": [SeedConstants.SINGLE_SIG],
|
||||
"m": [SeedConstants.MULTISIG],
|
||||
"b": [SeedConstants.SINGLE_SIG, SeedConstants.MULTISIG]
|
||||
"s": SeedConstants.SINGLE_SIG,
|
||||
"m": SeedConstants.MULTISIG,
|
||||
}
|
||||
map_abbreviated_scripts = {
|
||||
"na": SeedConstants.NATIVE_SEGWIT,
|
||||
@@ -696,13 +697,18 @@ class SettingsQR:
|
||||
"tr": SeedConstants.TAPROOT,
|
||||
"cu": SeedConstants.CUSTOM_DERIVATION,
|
||||
}
|
||||
map_abbreviated_coordinators = {
|
||||
"bw": SettingsConstants.COORDINATOR__BLUE_WALLET,
|
||||
"sw": SettingsConstants.COORDINATOR__SPARROW,
|
||||
"sd": SettingsConstants.COORDINATOR__SPECTER_DESKTOP,
|
||||
}
|
||||
|
||||
def convert_abbreviated_value(category, key, abbreviation_map, is_list=False, new_key_name=None):
|
||||
try:
|
||||
if category not in self.settings or key not in self.settings[category]:
|
||||
logger.debug(f"{category} / {key} not found in settings")
|
||||
if key not in self.settings:
|
||||
logger.debug(f"'{key}' not found in settings")
|
||||
return
|
||||
value = self.settings[category][key]
|
||||
value = self.settings[key]
|
||||
|
||||
if not is_list:
|
||||
new_value = abbreviation_map.get(value)
|
||||
@@ -710,7 +716,7 @@ class SettingsQR:
|
||||
logger.error(f"No abbreviation map value for \"{value}\" for setting {key}")
|
||||
return
|
||||
else:
|
||||
# `value` is actually a comma-separated list; yielda list of map matches
|
||||
# `value` is a comma-separated list; yields list of map matches
|
||||
values = value.split(",")
|
||||
new_value = []
|
||||
for v in values:
|
||||
@@ -719,16 +725,19 @@ class SettingsQR:
|
||||
logger.error(f"No abbreviation map value for \"{v}\" for setting {key}")
|
||||
return
|
||||
new_value.append(mapped_value)
|
||||
del self.settings[key]
|
||||
if new_key_name:
|
||||
del self.settings[category][key]
|
||||
key = new_key_name
|
||||
if category not in self.settings:
|
||||
self.settings[category] = {}
|
||||
self.settings[category][key] = new_value
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
return
|
||||
|
||||
convert_abbreviated_value("wallet", "coord", map_abbreviated_coordinators, is_list=True, new_key_name="coordinators")
|
||||
convert_abbreviated_value("features", "xpub", map_abbreviated_enable, new_key_name="xpub_export")
|
||||
convert_abbreviated_value("features", "sigs", map_abbreviated_sig_types, new_key_name="sig_types")
|
||||
convert_abbreviated_value("features", "sigs", map_abbreviated_sig_types, is_list=True, new_key_name="sig_types")
|
||||
convert_abbreviated_value("features", "scripts", map_abbreviated_scripts, is_list=True, new_key_name="script_types")
|
||||
convert_abbreviated_value("features", "passphrase", map_abbreviated_enable)
|
||||
convert_abbreviated_value("features", "priv_warn", map_abbreviated_enable, new_key_name="privacy_warnings")
|
||||
|
||||
@@ -1,26 +1,25 @@
|
||||
import configparser
|
||||
import json
|
||||
import os
|
||||
|
||||
from embit import bip39
|
||||
from typing import List
|
||||
|
||||
from .seed import SeedConstants
|
||||
from .singleton import ConfigurableSingleton
|
||||
from .singleton import Singleton
|
||||
from .qr_type import QRType
|
||||
from .encode_qr_density import EncodeQRDensity
|
||||
|
||||
|
||||
|
||||
class SettingsConstants:
|
||||
COORDINATOR__SPECTER_DESKTOP = "Specter Desktop"
|
||||
COORDINATOR__BLUE_WALLET = "BlueWallet"
|
||||
COORDINATOR__SPARROW = "Sparrow"
|
||||
COORDINATOR__PROMPT = "Prompt"
|
||||
COORDINATOR__SPECTER_DESKTOP = "Specter Desktop"
|
||||
|
||||
ALL_COORDINATORS = [
|
||||
COORDINATOR__SPECTER_DESKTOP,
|
||||
COORDINATOR__BLUE_WALLET,
|
||||
COORDINATOR__SPARROW,
|
||||
COORDINATOR__PROMPT,
|
||||
COORDINATOR__SPECTER_DESKTOP,
|
||||
]
|
||||
|
||||
OPTION__ENABLED = "Enabled"
|
||||
@@ -35,70 +34,70 @@ class SettingsConstants:
|
||||
|
||||
|
||||
|
||||
class Settings(ConfigurableSingleton):
|
||||
class Settings(Singleton):
|
||||
SETTINGS_FILENAME = "settings.json"
|
||||
|
||||
@classmethod
|
||||
def configure_instance(cls, config: configparser.ConfigParser = None):
|
||||
super().configure_instance(config)
|
||||
def get_instance(cls):
|
||||
# This is the only way to access the one and only instance
|
||||
if cls._instance is None:
|
||||
# Instantiate the one and only instance
|
||||
settings = cls.__new__(cls)
|
||||
cls._instance = settings
|
||||
|
||||
# Instantiate the one and only instance
|
||||
settings = cls.__new__(cls)
|
||||
cls._instance = settings
|
||||
|
||||
# default internal data structure for settings
|
||||
settings._data = {
|
||||
"system": {
|
||||
"debug": False,
|
||||
"default_language": "en",
|
||||
"persistent_settings": False,
|
||||
"wordlist": bip39.WORDLIST # TODO: Just store the wordlist language
|
||||
},
|
||||
"display": {
|
||||
"text_color": "white",
|
||||
"background_color": "black",
|
||||
"camera_rotation": 0,
|
||||
},
|
||||
"wallet": {
|
||||
"network": SeedConstants.MAINNET,
|
||||
"software": SettingsConstants.COORDINATOR__SPECTER_DESKTOP,
|
||||
"qr_density": EncodeQRDensity.MEDIUM,
|
||||
"custom_derivation": "m/"
|
||||
},
|
||||
"features": {
|
||||
"xpub_export": SettingsConstants.OPTION__ENABLED, # ENABLED | DISABLED
|
||||
"sig_types": SeedConstants.ALL_SIG_TYPES, # [single_sig, multisig]
|
||||
"script_types": [t["type"] for t in SeedConstants.ALL_SCRIPT_TYPES], # [script_type1, ...]
|
||||
"passphrase": SettingsConstants.OPTION__PROMPT, # ENABLED | DISABLED | PROMPT
|
||||
"privacy_warnings": SettingsConstants.OPTION__ENABLED, # ENABLED | DISABLED
|
||||
"dire_warnings": SettingsConstants.OPTION__ENABLED, # ENABLED | DISABLED
|
||||
# default internal data structure for settings
|
||||
settings._data = {
|
||||
"system": {
|
||||
"debug": False,
|
||||
"default_language": "en",
|
||||
"persistent_settings": False,
|
||||
},
|
||||
"display": {
|
||||
"text_color": "white",
|
||||
"background_color": "black",
|
||||
"camera_rotation": 0,
|
||||
},
|
||||
"wallet": {
|
||||
"network": SeedConstants.MAINNET,
|
||||
"coordinators": SettingsConstants.ALL_COORDINATORS,
|
||||
"qr_density": EncodeQRDensity.MEDIUM,
|
||||
"custom_derivation": "m/"
|
||||
},
|
||||
"features": {
|
||||
"xpub_export": SettingsConstants.OPTION__ENABLED, # ENABLED | DISABLED
|
||||
"sig_types": SeedConstants.ALL_SIG_TYPES, # [single_sig, multisig]
|
||||
"script_types": [t["type"] for t in SeedConstants.ALL_SCRIPT_TYPES], # [script_type1, ...]
|
||||
"passphrase": SettingsConstants.OPTION__PROMPT, # ENABLED | DISABLED | PROMPT
|
||||
"privacy_warnings": SettingsConstants.OPTION__ENABLED, # ENABLED | DISABLED
|
||||
"dire_warnings": SettingsConstants.OPTION__ENABLED, # ENABLED | DISABLED
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
settings.init_complete = False
|
||||
# Read persistent settings, if it exists
|
||||
if os.path.exists(Settings.SETTINGS_FILENAME):
|
||||
with open(Settings.SETTINGS_FILENAME) as settings_file:
|
||||
settings._data.update(json.load(settings_file))
|
||||
|
||||
if config is not None:
|
||||
# read settings.ini typically
|
||||
settings.__config_to_data(config)
|
||||
return cls._instance
|
||||
|
||||
settings.init_complete = True
|
||||
|
||||
def __str__(self):
|
||||
return json.dumps(self._data, indent=2)
|
||||
|
||||
def __config_to_data(self, config: configparser.ConfigParser):
|
||||
self.persistent = config.getboolean("system", "persistent_settings")
|
||||
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"])
|
||||
self.custom_derivation = config["wallet"]["custom_derivation"]
|
||||
|
||||
|
||||
def save(self):
|
||||
if self._data["system"]["persistent_settings"] == True and self.init_complete == True:
|
||||
with open(Settings.SETTINGS_FILENAME, 'w') as settings_file:
|
||||
json.dump(self._data, settings_file)
|
||||
|
||||
|
||||
def update(self, new_settings: dict):
|
||||
self._data.update(new_settings)
|
||||
# Can't just merge the _data dict; have to replace keys they have in common
|
||||
# (otherwise list values will be merged instead of replaced).
|
||||
for category, category_settings in new_settings.items():
|
||||
for key, value in category_settings.items():
|
||||
self._data[category].pop(key, None)
|
||||
self._data[category][key] = value
|
||||
|
||||
|
||||
### persistent settings handling
|
||||
@@ -108,42 +107,17 @@ class Settings(ConfigurableSingleton):
|
||||
return self._data["system"]["persistent_settings"]
|
||||
|
||||
@persistent.setter
|
||||
def persistent(self, value):
|
||||
def persistent(self, value: bool):
|
||||
if type(value) == bool:
|
||||
if value == False and value != self._data["system"]["persistent_settings"]:
|
||||
# persistence is changed to false, restore defaults
|
||||
self._data["system"]["persistent_settings"] = value
|
||||
self.init_complete == False
|
||||
self.restoreDefault()
|
||||
self.init_complete == True
|
||||
self._data["system"]["persistent_settings"] = value
|
||||
if value:
|
||||
self.save()
|
||||
else:
|
||||
self._data["system"]["persistent_settings"] = value
|
||||
self.__writeConfig()
|
||||
# persistence is changed to false, remove SETTINGS_FILE
|
||||
if os.path.exists(Settings.SETTINGS_FILENAME):
|
||||
os.remove(Settings.SETTINGS_FILENAME)
|
||||
else:
|
||||
raise Exception("Unexpected system.persistent_settings settings.ini value")
|
||||
|
||||
def restoreDefault(self):
|
||||
config = configparser.ConfigParser()
|
||||
config.read("default_settings.ini")
|
||||
self.__config_to_data(config)
|
||||
self.__writeSettingsIni(config)
|
||||
|
||||
def __writeSettingsIni(self, config):
|
||||
with open('settings.ini', 'w') as configfile:
|
||||
config.write(configfile)
|
||||
configfile.close()
|
||||
|
||||
def __generateConfig(self):
|
||||
config = configparser.ConfigParser()
|
||||
config['system'] = self._data['system']
|
||||
config['display'] = self._data['display']
|
||||
config['wallet'] = self._data['wallet']
|
||||
return config
|
||||
|
||||
def __writeConfig(self):
|
||||
if self._data["system"]["persistent_settings"] == True and self.init_complete == True:
|
||||
config = self.__generateConfig()
|
||||
self.__writeSettingsIni(config)
|
||||
raise Exception("Unexpected system.persistent_settings settings.json value")
|
||||
|
||||
@property
|
||||
def persistent_display(self):
|
||||
@@ -164,7 +138,8 @@ class Settings(ConfigurableSingleton):
|
||||
|
||||
@property
|
||||
def wordlist(self):
|
||||
return self._data["system"]["wordlist"]
|
||||
# TODO: Support BIP-39 wordlists in other languages
|
||||
return bip39.WORDLIST
|
||||
|
||||
### display
|
||||
|
||||
@@ -177,12 +152,12 @@ class Settings(ConfigurableSingleton):
|
||||
return self._data["display"]["camera_rotation"]
|
||||
|
||||
@camera_rotation.setter
|
||||
def camera_rotation(self, value):
|
||||
def camera_rotation(self, value: int):
|
||||
if value in [0, 90, 180, 270]:
|
||||
self._data["display"]["camera_rotation"] = value
|
||||
self.__writeConfig()
|
||||
self.save()
|
||||
else:
|
||||
raise Exception("Unexpected display.camera_rotation settings.ini value")
|
||||
raise Exception("Unexpected display.camera_rotation settings.json value")
|
||||
|
||||
### wallet
|
||||
|
||||
@@ -194,9 +169,13 @@ class Settings(ConfigurableSingleton):
|
||||
def network(self, value):
|
||||
if value in [SeedConstants.MAINNET, SeedConstants.TESTNET]:
|
||||
self._data["wallet"]["network"] = value
|
||||
self.__writeConfig()
|
||||
self.save()
|
||||
else:
|
||||
raise Exception("Unexpected wallet.network settings.ini value")
|
||||
raise Exception("Unexpected wallet.network settings.json value")
|
||||
|
||||
@property
|
||||
def coordinators(self):
|
||||
return self._data["wallet"]["coordinators"]
|
||||
|
||||
@property
|
||||
def software(self):
|
||||
@@ -206,9 +185,9 @@ class Settings(ConfigurableSingleton):
|
||||
def software(self, value):
|
||||
if value in SettingsConstants.ALL_COORDINATORS:
|
||||
self._data["wallet"]["software"] = value
|
||||
self.__writeConfig()
|
||||
self.save()
|
||||
else:
|
||||
raise Exception("Unexpected wallet.software settings.ini value")
|
||||
raise Exception("Unexpected wallet.software settings.json value")
|
||||
|
||||
@property
|
||||
def qr_density(self):
|
||||
@@ -218,9 +197,9 @@ class Settings(ConfigurableSingleton):
|
||||
def qr_density(self, value):
|
||||
if value in (EncodeQRDensity.LOW, EncodeQRDensity.MEDIUM, EncodeQRDensity.HIGH, int(EncodeQRDensity.LOW), int(EncodeQRDensity.MEDIUM), int(EncodeQRDensity.HIGH)):
|
||||
self._data["wallet"]["qr_density"] = int(value)
|
||||
self.__writeConfig()
|
||||
self.save()
|
||||
else:
|
||||
raise Exception("Unexpected wallet.qr_density settings.ini value")
|
||||
raise Exception("Unexpected wallet.qr_density settings.json value")
|
||||
|
||||
@property
|
||||
def qr_psbt_type(self):
|
||||
@@ -259,7 +238,7 @@ class Settings(ConfigurableSingleton):
|
||||
def custom_derivation(self, value):
|
||||
# TODO: parse and validate custom derivation path
|
||||
self._data["wallet"]["custom_derivation"] = value
|
||||
self.__writeConfig()
|
||||
self.save()
|
||||
|
||||
@staticmethod
|
||||
def calc_derivation(network, wallet_type, script_type):
|
||||
@@ -295,17 +274,25 @@ class Settings(ConfigurableSingleton):
|
||||
|
||||
# Features
|
||||
@property
|
||||
def export_xpub(self):
|
||||
self._data["features"].get("export_xpub")
|
||||
def xpub_export(self):
|
||||
return self._data["features"].get("xpub_export")
|
||||
|
||||
@property
|
||||
def sig_types(self) -> List[str]:
|
||||
return self._data["features"].get("sig_types")
|
||||
|
||||
@property
|
||||
def script_types(self) -> List[str]:
|
||||
return self._data["features"].get("script_types")
|
||||
|
||||
@property
|
||||
def passphrase(self):
|
||||
self._data["features"].get("passphrase")
|
||||
return self._data["features"].get("passphrase")
|
||||
|
||||
@property
|
||||
def privacy_warnings(self):
|
||||
self._data["features"].get("privacy_warnings")
|
||||
return self._data["features"].get("privacy_warnings")
|
||||
|
||||
@property
|
||||
def dire_warnings(self):
|
||||
self._data["features"].get("dire_warnings")
|
||||
return self._data["features"].get("dire_warnings")
|
||||
|
||||
@@ -56,7 +56,8 @@ class SeedOptionsView(View):
|
||||
|
||||
button_data = ["View Seed Words"]
|
||||
|
||||
if self.settings.export_xpub == SettingsConstants.OPTION__ENABLED:
|
||||
print(f"{self.settings.xpub_export} == {SettingsConstants.OPTION__ENABLED}")
|
||||
if self.settings.xpub_export == SettingsConstants.OPTION__ENABLED:
|
||||
button_data.append("Export Xpub")
|
||||
|
||||
button_data.append("Export Seed as QR")
|
||||
@@ -72,8 +73,8 @@ class SeedOptionsView(View):
|
||||
# View seed words
|
||||
return Destination(ShowSeedWordsWarningView, view_args={"seed_num": self.seed_num})
|
||||
|
||||
elif selected_menu_num == 1 and self.settings.export_xpub == SettingsConstants.OPTION__ENABLED:
|
||||
return Destination(SeedExportXpubSigTypeView, view_args={"seed_num": self.seed_num})
|
||||
elif selected_menu_num == 1 and self.settings.xpub_export == SettingsConstants.OPTION__ENABLED:
|
||||
return Destination(SeedExportXpubSigTypeView, view_args={"seed_num": self.seed_num})
|
||||
|
||||
elif selected_menu_num == len(button_data) - 1:
|
||||
# TODO: Export Seed as QR
|
||||
@@ -120,6 +121,10 @@ class SeedExportXpubSigTypeView(View):
|
||||
|
||||
|
||||
def run(self):
|
||||
if len(self.settings.sig_types) == 1:
|
||||
# Nothing to select; skip this screen
|
||||
return Destination(SeedExportXpubScriptTypeView, view_args={"seed_num": self.seed_num, "sig_type": self.settings.sig_types[0]}, skip_current_view=True)
|
||||
|
||||
screen = LargeButtonScreen(
|
||||
title="Export Xpub",
|
||||
button_data=[
|
||||
@@ -148,6 +153,12 @@ class SeedExportXpubScriptTypeView(View):
|
||||
|
||||
|
||||
def run(self):
|
||||
args = {"seed_num": self.seed_num, "sig_type": self.sig_type}
|
||||
if len(self.settings.sig_types) == 1:
|
||||
# Nothing to select; skip this screen
|
||||
args["script_type"] = self.settings.script_types[0]
|
||||
return Destination(SeedExportXpubCoordinatorView, view_args=args, skip_current_view=True)
|
||||
|
||||
screen = ButtonListScreen(
|
||||
title="Export Xpub",
|
||||
is_button_text_centered=False,
|
||||
@@ -156,8 +167,6 @@ class SeedExportXpubScriptTypeView(View):
|
||||
)
|
||||
selected_menu_num = screen.display()
|
||||
|
||||
args = {"seed_num": self.seed_num, "sig_type": self.sig_type}
|
||||
|
||||
if selected_menu_num < len(SeedConstants.ALL_SCRIPT_TYPES):
|
||||
args["script_type"] = SeedConstants.ALL_SCRIPT_TYPES[selected_menu_num]["type"]
|
||||
|
||||
@@ -211,35 +220,26 @@ class SeedExportXpubCoordinatorView(View):
|
||||
|
||||
|
||||
def run(self):
|
||||
default_coordinator = self.settings.software
|
||||
|
||||
# Set up how the list should be ordered
|
||||
coordinator_list = []
|
||||
if default_coordinator == SettingsConstants.COORDINATOR__PROMPT:
|
||||
# Use the default list, but omit "Prompt"
|
||||
coordinator_list = SettingsConstants.ALL_COORDINATORS[:-1]
|
||||
else:
|
||||
# List the selected coordinator first, then the rest (but omit "Prompt")
|
||||
coordinator_list.append(default_coordinator)
|
||||
for coordinator in SettingsConstants.ALL_COORDINATORS[:-1]:
|
||||
if coordinator != default_coordinator:
|
||||
coordinator_list.append(coordinator)
|
||||
args = {
|
||||
"seed_num": self.seed_num,
|
||||
"sig_type": self.sig_type,
|
||||
"script_type": self.script_type,
|
||||
}
|
||||
if len(self.settings.coordinators) == 1:
|
||||
# Nothing to select; skip this screen
|
||||
args["coordinator"] = self.settings.coordinators[0]
|
||||
return Destination(SeedExportXpubWarningView, view_args=args, skip_current_view=True)
|
||||
|
||||
screen = ButtonListScreen(
|
||||
title="Export Xpub",
|
||||
is_button_text_centered=False,
|
||||
is_bottom_list=True,
|
||||
button_data=coordinator_list,
|
||||
button_data=self.settings.coordinators,
|
||||
)
|
||||
selected_menu_num = screen.display()
|
||||
|
||||
if selected_menu_num < len(coordinator_list):
|
||||
args = {
|
||||
"seed_num": self.seed_num,
|
||||
"sig_type": self.sig_type,
|
||||
"script_type": self.script_type,
|
||||
"coordinator": SettingsConstants.ALL_COORDINATORS[selected_menu_num],
|
||||
}
|
||||
if selected_menu_num < len(self.settings.coordinators):
|
||||
args["coordinator"] = self.settings.coordinators[selected_menu_num]
|
||||
return Destination(SeedExportXpubWarningView, view_args=args)
|
||||
|
||||
elif selected_menu_num == RET_CODE__BACK_BUTTON:
|
||||
|
||||
@@ -97,6 +97,7 @@ class Destination:
|
||||
"""
|
||||
View_cls: View # The target View to route to
|
||||
view_args: dict = None # The input args required to instantiate the target View
|
||||
skip_current_view: bool = False # The current View is just forwarding; omit current View from history
|
||||
clear_history: bool = False # Optionally clears the back_stack to prevent "back"
|
||||
|
||||
def __str__(self):
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
[system]
|
||||
debug = True
|
||||
default_language = en
|
||||
persistent_settings = True
|
||||
|
||||
[display]
|
||||
text_color = ORANGE
|
||||
camera_rotation = 0
|
||||
|
||||
[wallet]
|
||||
network = main
|
||||
software = Prompt
|
||||
qr_density = 2
|
||||
custom_derivation = m/
|
||||
Reference in New Issue
Block a user