You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
139 lines
5.1 KiB
139 lines
5.1 KiB
# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. <hello@foundationdevices.com>
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
#
|
|
# accounts.py - Single sig and multisig accounts feature for better organization and privacy/isolation
|
|
#
|
|
|
|
from menu import MenuSystem, MenuItem
|
|
from flow import SettingsMenu, AccountMenu
|
|
import stash
|
|
import common
|
|
from common import settings, system
|
|
from utils import UXStateMachine, to_json, to_str, save_new_account, make_account_name_num, account_exists, get_accounts
|
|
from wallets.utils import get_next_account_num
|
|
from ux import ux_enter_text, ux_show_story
|
|
from constants import DEFAULT_ACCOUNT_ENTRY, MAX_ACCOUNT_NAME_LEN
|
|
|
|
# from wallets.constants import *
|
|
|
|
# Set the account reference in common and update xfp/xpub with the current account
|
|
def set_active_account(label=None, arg=None, menu_title=None, index=None):
|
|
account = arg
|
|
# print('Setting active_account={}'.format(account))
|
|
common.active_account = account
|
|
|
|
def clear_active_account(label=None, arg=None, menu_title=None, index=None):
|
|
# print('Clearing active_account')
|
|
common.active_account = None
|
|
|
|
async def new_account(*a):
|
|
new_account_ux = NewAccountUX()
|
|
await new_account_ux.show()
|
|
|
|
|
|
class NewAccountUX(UXStateMachine):
|
|
def __init__(self):
|
|
# States
|
|
self.SELECT_ACCOUNT_NUM = 1
|
|
self.ENTER_ACCOUNT_NAME = 2
|
|
|
|
self.account_num = 0
|
|
self.account_name = ''
|
|
super().__init__(self.SELECT_ACCOUNT_NUM)
|
|
|
|
async def show(self):
|
|
while True:
|
|
# print('show: state={}'.format(self.state))
|
|
if self.state == self.SELECT_ACCOUNT_NUM:
|
|
# Pick the next expected acct_num as the default value here
|
|
next_acct_num = get_next_account_num()
|
|
|
|
acct_num = await ux_enter_text(
|
|
title="Account",
|
|
label="Account Number",
|
|
initial_text='{}'.format(next_acct_num),
|
|
left_btn='BACK',
|
|
right_btn='ENTER',
|
|
num_only=True,
|
|
max_length=9)
|
|
|
|
if acct_num == None:
|
|
return
|
|
|
|
# Use the entered account number
|
|
self.account_num = acct_num
|
|
|
|
self.goto(self.ENTER_ACCOUNT_NAME)
|
|
|
|
elif self.state == self.ENTER_ACCOUNT_NAME:
|
|
name = await ux_enter_text(
|
|
'Account Name',
|
|
label='New Account Name',
|
|
initial_text=self.account_name,
|
|
right_btn='SAVE',
|
|
max_length=MAX_ACCOUNT_NAME_LEN)
|
|
if name == None:
|
|
self.goto_prev()
|
|
continue
|
|
|
|
# See if an account with this name already exists
|
|
if account_exists(name):
|
|
result = await ux_show_story('An account with the name "{}" already exists. Please choose a different name.'.format(name),
|
|
title='Duplicate', center=True, center_vertically=True, right_btn='EDIT')
|
|
if result == 'x':
|
|
self.goto_prev()
|
|
continue
|
|
else:
|
|
self.account_name = name # Start off with the name the user entered
|
|
continue
|
|
|
|
await save_new_account(name, self.account_num)
|
|
return
|
|
|
|
MAX_ACCOUNTS = 20
|
|
def max_accounts_reached():
|
|
accounts = get_accounts()
|
|
return len(accounts) >= MAX_ACCOUNTS
|
|
|
|
class AllAccountsMenu(MenuSystem):
|
|
|
|
@classmethod
|
|
def construct(cls):
|
|
# Dynamic menu with user-defined names of accounts
|
|
# from actions import import_multisig_from_sd, import_multisig_from_qr
|
|
|
|
rv = []
|
|
try:
|
|
accounts = get_accounts()
|
|
|
|
# print('accounts={}'.format(to_str(accounts)))
|
|
|
|
for acct in accounts:
|
|
acct_num = acct.get('acct_num')
|
|
name_num = make_account_name_num(acct.get('name'), acct_num)
|
|
rv.append(
|
|
MenuItem(
|
|
name_num,
|
|
menu=AccountMenu,
|
|
menu_title=name_num,
|
|
action=set_active_account,
|
|
arg=acct))
|
|
|
|
# Show Resume or new account menu depending on status
|
|
rv.append(MenuItem('New Account', f=new_account, predicate=lambda: not max_accounts_reached()))
|
|
except Exception as e:
|
|
# print('accounts={}'.format(accounts))
|
|
print('e={}'.format(e))
|
|
rv.append(MenuItem('<Account Data Corrupted>', f=lambda: None))
|
|
|
|
# print('rv={}'.format(rv))
|
|
return rv
|
|
|
|
def update_contents(self):
|
|
# Reconstruct the list of wallets on this dynamic menu, because
|
|
# we added or changed them and are showing that same menu again.
|
|
tmp = self.construct()
|
|
self.replace_items(tmp, True)
|
|
# Clear active account, if any, usually when menu is activated after returning from an account submenu
|
|
if common.active_account != None:
|
|
clear_active_account()
|
|
|