1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-02-24 05:12:02 +00:00

apps: use mutable Text API

This commit is contained in:
Jan Pochyla 2018-07-02 15:19:04 +02:00
parent 49e75851c7
commit b3d3da7f7a
28 changed files with 289 additions and 295 deletions

View File

@ -10,10 +10,11 @@ from trezor.utils import chunks
async def show_address(ctx, address: str): async def show_address(ctx, address: str):
lines = split_address(address) lines = split_address(address)
content = Text('Confirm address', ui.ICON_RECEIVE, ui.MONO, *lines, icon_color=ui.GREEN) text = Text('Confirm address', ui.ICON_RECEIVE, icon_color=ui.GREEN)
text.mono(*lines)
return await confirm( return await confirm(
ctx, ctx,
content, text,
code=ButtonRequestType.Address, code=ButtonRequestType.Address,
cancel='QR', cancel='QR',
cancel_style=ui.BTN_KEY) cancel_style=ui.BTN_KEY)
@ -24,9 +25,9 @@ async def show_qr(ctx, address: str):
qr_y = const(115) qr_y = const(115)
qr_coef = const(4) qr_coef = const(4)
content = Container( qr = Qr(address, (qr_x, qr_y), qr_coef)
Qr(address, (qr_x, qr_y), qr_coef), text = Text('Confirm address', ui.ICON_RECEIVE, icon_color=ui.GREEN)
Text('Confirm address', ui.ICON_RECEIVE, ui.MONO, icon_color=ui.GREEN)) content = Container(qr, text)
return await confirm( return await confirm(
ctx, ctx,
content, content,

View File

@ -13,9 +13,8 @@ from apps.common.cache import get_state
@ui.layout @ui.layout
async def request_passphrase_entry(ctx): async def request_passphrase_entry(ctx):
text = Text( text = Text('Enter passphrase', ui.ICON_CONFIG)
'Enter passphrase', ui.ICON_CONFIG, text.type('Where to enter your', 'passphrase?')
'Where to enter your', 'passphrase?')
text.render() text.render()
ack = await ctx.call( ack = await ctx.call(
@ -32,9 +31,8 @@ async def request_passphrase_entry(ctx):
@ui.layout @ui.layout
async def request_passphrase_ack(ctx, on_device): async def request_passphrase_ack(ctx, on_device):
if not on_device: if not on_device:
text = Text( text = Text('Passphrase entry', ui.ICON_CONFIG)
'Passphrase entry', ui.ICON_CONFIG, text.type('Please, type passphrase', 'on connected host.')
'Please, type passphrase', 'on connected host.')
text.render() text.render()
req = PassphraseRequest(on_device=on_device) req = PassphraseRequest(on_device=on_device)

View File

@ -12,26 +12,25 @@ from apps.ethereum.get_address import _ethereum_address_hex
async def require_confirm_tx(ctx, to, value, chain_id, token=None, tx_type=None): async def require_confirm_tx(ctx, to, value, chain_id, token=None, tx_type=None):
if to: if to:
str_to = _ethereum_address_hex(to, networks.by_chain_id(chain_id)) to_str = _ethereum_address_hex(to, networks.by_chain_id(chain_id))
else: else:
str_to = 'new contract?' to_str = 'new contract?'
content = Text('Confirm sending', ui.ICON_SEND, text = Text('Confirm sending', ui.ICON_SEND, icon_color=ui.GREEN)
ui.BOLD, format_ethereum_amount(value, token, chain_id, tx_type), text.bold(format_ethereum_amount(value, token, chain_id, tx_type))
ui.NORMAL, 'to', text.type('to')
ui.MONO, *split_address(str_to), text.mono(*split_address(to_str))
icon_color=ui.GREEN) # we use SignTx, not ConfirmOutput, for compatibility with T1
await require_confirm(ctx, content, ButtonRequestType.SignTx) # we use SignTx, not ConfirmOutput, for compatibility with T1 await require_confirm(ctx, text, ButtonRequestType.SignTx)
async def require_confirm_fee(ctx, spending, gas_price, gas_limit, chain_id, token=None, tx_type=None): async def require_confirm_fee(ctx, spending, gas_price, gas_limit, chain_id, token=None, tx_type=None):
content = Text('Confirm transaction', ui.ICON_SEND, text = Text('Confirm transaction', ui.ICON_SEND, icon_color=ui.GREEN)
ui.BOLD, format_ethereum_amount(spending, token, chain_id, tx_type), text.bold(format_ethereum_amount(spending, token, chain_id, tx_type))
ui.NORMAL, 'Gas price:', text.type('Gas price:')
ui.BOLD, format_ethereum_amount(gas_price, None, chain_id, tx_type), text.bold(format_ethereum_amount(gas_price, None, chain_id, tx_type))
ui.NORMAL, 'Maximum fee:', text.type('Maximum fee:')
ui.BOLD, format_ethereum_amount(gas_price * gas_limit, None, chain_id, tx_type), text.bold(format_ethereum_amount(gas_price * gas_limit, None, chain_id, tx_type))
icon_color=ui.GREEN) await require_hold_to_confirm(ctx, text, ButtonRequestType.SignTx)
await require_hold_to_confirm(ctx, content, ButtonRequestType.SignTx)
def split_data(data): def split_data(data):
@ -39,14 +38,14 @@ def split_data(data):
async def require_confirm_data(ctx, data, data_total): async def require_confirm_data(ctx, data, data_total):
str_data = hexlify(data[:36]).decode() data_str = hexlify(data[:36]).decode()
if data_total > 36: if data_total > 36:
str_data = str_data[:-2] + '..' data_str = data_str[:-2] + '..'
content = Text('Confirm data', ui.ICON_SEND, text = Text('Confirm data', ui.ICON_SEND, icon_color=ui.GREEN)
ui.BOLD, 'Size: %d bytes' % data_total, text.bold('Size: %d bytes' % data_total)
ui.MONO, *split_data(str_data), text.mono(*split_data(data_str))
icon_color=ui.GREEN) # we use SignTx, not ConfirmOutput, for compatibility with T1
await require_confirm(ctx, content, ButtonRequestType.SignTx) # we use SignTx, not ConfirmOutput, for compatibility with T1 await require_confirm(ctx, text, ButtonRequestType.SignTx)
def split_address(address): def split_address(address):

View File

@ -37,5 +37,6 @@ async def ethereum_sign_message(ctx, msg):
async def require_confirm_sign_message(ctx, message): async def require_confirm_sign_message(ctx, message):
message = split_message(message) message = split_message(message)
content = Text('Sign ETH message', ui.ICON_DEFAULT, max_lines=5, *message) text = Text('Sign ETH message', ui.ICON_DEFAULT)
await require_confirm(ctx, content) text.type(*message)
await require_confirm(ctx, text)

View File

@ -32,10 +32,10 @@ async def ethereum_verify_message(ctx, msg):
async def require_confirm_verify_message(ctx, address, message): async def require_confirm_verify_message(ctx, address, message):
lines = split_address(address) text = Text('Confirm address', ui.ICON_DEFAULT)
content = Text('Confirm address', ui.ICON_DEFAULT, ui.MONO, *lines) text.mono(*split_address(address))
await require_confirm(ctx, content) await require_confirm(ctx, text)
message = split_message(message) text = Text('Verify message', ui.ICON_DEFAULT)
content = Text('Verify message', ui.ICON_DEFAULT, max_lines=5, *message) text.mono(*split_message(message))
await require_confirm(ctx, content) await require_confirm(ctx, text)

View File

@ -391,12 +391,8 @@ class ConfirmState:
from trezor.ui.text import Text from trezor.ui.text import Text
if bytes(self.app_id) == _BOGUS_APPID: if bytes(self.app_id) == _BOGUS_APPID:
text = Text( text = Text('U2F mismatch', ui.ICON_WRONG, icon_color=ui.RED)
'U2F mismatch', ui.ICON_WRONG, text.type('Another U2F device', 'was used to register', 'in this application.')
'Another U2F device',
'was used to register',
'in this application.',
icon_color=ui.RED)
text.render() text.render()
await loop.sleep(3 * 1000 * 1000) await loop.sleep(3 * 1000 * 1000)
self.confirmed = True self.confirmed = True

View File

@ -9,28 +9,25 @@ from .helpers import get_vote_tx_text
async def require_confirm_tx(ctx, to, value): async def require_confirm_tx(ctx, to, value):
content = Text('Confirm sending', ui.ICON_SEND, text = Text('Confirm sending', ui.ICON_SEND, icon_color=ui.GREEN)
ui.BOLD, format_amount(value), text.bold(format_amount(value))
ui.NORMAL, 'to', text.type('to')
ui.MONO, *split_address(to), text.mono(*split_address(to))
icon_color=ui.GREEN) return await require_confirm(ctx, text, ButtonRequestType.SignTx)
return await require_confirm(ctx, content, ButtonRequestType.SignTx)
async def require_confirm_delegate_registration(ctx, delegate_name): async def require_confirm_delegate_registration(ctx, delegate_name):
content = Text('Confirm transaction', ui.ICON_SEND, text = Text('Confirm transaction', ui.ICON_SEND, icon_color=ui.GREEN)
'Do you really want to', text.type('Do you really want to')
'register a delegate?', text.type('register a delegate?')
ui.BOLD, *chunks(delegate_name, 20), text.bold(*chunks(delegate_name, 20))
icon_color=ui.GREEN) return await require_confirm(ctx, text, ButtonRequestType.SignTx)
return await require_confirm(ctx, content, ButtonRequestType.SignTx)
async def require_confirm_vote_tx(ctx, votes): async def require_confirm_vote_tx(ctx, votes):
content = Text('Confirm transaction', ui.ICON_SEND, text = Text('Confirm transaction', ui.ICON_SEND, icon_color=ui.GREEN)
*get_vote_tx_text(votes), text.type(*get_vote_tx_text(votes))
icon_color=ui.GREEN) return await require_confirm(ctx, text, ButtonRequestType.SignTx)
return await require_confirm(ctx, content, ButtonRequestType.SignTx)
async def require_confirm_public_key(ctx, public_key): async def require_confirm_public_key(ctx, public_key):
@ -38,21 +35,19 @@ async def require_confirm_public_key(ctx, public_key):
async def require_confirm_multisig(ctx, multisignature): async def require_confirm_multisig(ctx, multisignature):
content = Text('Confirm transaction', ui.ICON_SEND, text = Text('Confirm transaction', ui.ICON_SEND, icon_color=ui.GREEN)
('Keys group length: %s' % len(multisignature.keys_group)), text.type('Keys group length: %s' % len(multisignature.keys_group))
('Life time: %s' % multisignature.life_time), text.type('Life time: %s' % multisignature.life_time)
('Min: %s' % multisignature.min), text.type('Min: %s' % multisignature.min)
icon_color=ui.GREEN) return await require_confirm(ctx, text, ButtonRequestType.SignTx)
return await require_confirm(ctx, content, ButtonRequestType.SignTx)
async def require_confirm_fee(ctx, value, fee): async def require_confirm_fee(ctx, value, fee):
content = Text('Confirm transaction', ui.ICON_SEND, text = Text('Confirm transaction', ui.ICON_SEND, icon_color=ui.GREEN)
ui.BOLD, format_amount(value), text.bold(format_amount(value))
ui.NORMAL, 'fee:', text.type('fee:')
ui.BOLD, format_amount(fee), text.bold(format_amount(fee))
icon_color=ui.GREEN) await require_hold_to_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
await require_hold_to_confirm(ctx, content, ButtonRequestType.ConfirmOutput)
def format_amount(value): def format_amount(value):

View File

@ -39,6 +39,6 @@ async def lisk_sign_message(ctx, msg):
async def require_confirm_sign_message(ctx, message): async def require_confirm_sign_message(ctx, message):
message = split_message(message) text = Text('Sign Lisk message', ui.ICON_DEFAULT)
content = Text('Sign Lisk message', ui.ICON_DEFAULT, max_lines=5, *message) text.type(*split_message(message))
await require_confirm(ctx, content) await require_confirm(ctx, text)

View File

@ -13,40 +13,16 @@ async def apply_settings(ctx, msg):
if msg.homescreen is not None: if msg.homescreen is not None:
if len(msg.homescreen) > storage.HOMESCREEN_MAXSIZE: if len(msg.homescreen) > storage.HOMESCREEN_MAXSIZE:
raise wire.DataError('Homescreen is too complex') raise wire.DataError('Homescreen is too complex')
await require_confirm(ctx, Text( await require_confirm_change_homescreen(ctx)
'Change homescreen', ui.ICON_CONFIG,
'Do you really want to', 'change homescreen?'),
code=ButtonRequestType.ProtectCall)
# TODO: split label (bold) and '?' (normal) once we support mixed styles on one line
if msg.label is not None: if msg.label is not None:
await require_confirm(ctx, Text( await require_confirm_change_label(ctx, msg.label)
'Change label', ui.ICON_CONFIG,
'Do you really want to', 'change label to',
ui.BOLD, '%s?' % msg.label),
code=ButtonRequestType.ProtectCall)
if msg.use_passphrase is not None: if msg.use_passphrase is not None:
await require_confirm(ctx, Text( await require_confirm_change_passphrase(ctx, msg.use_passphrase)
'Enable passphrase' if msg.use_passphrase else 'Disable passphrase',
ui.ICON_CONFIG,
'Do you really want to',
'enable passphrase' if msg.use_passphrase else 'disable passphrase',
'encryption?'),
code=ButtonRequestType.ProtectCall)
if msg.passphrase_source is not None: if msg.passphrase_source is not None:
if msg.passphrase_source == PassphraseSourceType.DEVICE: await require_confirm_change_passphrase_source(ctx, msg.passphrase_source)
desc = 'ON DEVICE'
elif msg.passphrase_source == PassphraseSourceType.HOST:
desc = 'ON HOST'
else:
desc = 'ASK'
await require_confirm(ctx, Text(
'Passphrase source', ui.ICON_CONFIG,
'Do you really want to', 'change the passphrase', 'source to',
ui.BOLD, 'ALWAYS %s?' % desc),
code=ButtonRequestType.ProtectCall)
storage.load_settings(label=msg.label, storage.load_settings(label=msg.label,
use_passphrase=msg.use_passphrase, use_passphrase=msg.use_passphrase,
@ -54,3 +30,37 @@ async def apply_settings(ctx, msg):
passphrase_source=msg.passphrase_source) passphrase_source=msg.passphrase_source)
return Success(message='Settings applied') return Success(message='Settings applied')
async def require_confirm_change_homescreen(ctx):
text = Text('Change homescreen', ui.ICON_CONFIG)
text.type('Do you really want to', 'change homescreen?')
await require_confirm(ctx, text, code=ButtonRequestType.ProtectCall)
async def require_confirm_change_label(ctx, label):
text = Text('Change label', ui.ICON_CONFIG)
text.type('Do you really want to', 'change label to')
text.bold('%s?' % label)
await require_confirm(ctx, text, code=ButtonRequestType.ProtectCall)
async def require_confirm_change_passphrase(ctx, use):
text = Text('Enable passphrase' if use else 'Disable passphrase', ui.ICON_CONFIG)
text.type('Do you really want to')
text.type('enable passphrase' if use else 'disable passphrase')
text.type('encryption?')
await require_confirm(ctx, text, code=ButtonRequestType.ProtectCall)
async def require_confirm_change_passphrase_source(ctx, source):
if source == PassphraseSourceType.DEVICE:
desc = 'ON DEVICE'
elif source == PassphraseSourceType.HOST:
desc = 'ON HOST'
else:
desc = 'ASK'
text = Text('Passphrase source', ui.ICON_CONFIG)
text.type('Do you really want to', 'change the passphrase', 'source to')
text.bold('ALWAYS %s?' % desc)
await require_confirm(ctx, text, code=ButtonRequestType.ProtectCall)

View File

@ -42,22 +42,22 @@ def require_confirm_change_pin(ctx, msg):
has_pin = config.has_pin() has_pin = config.has_pin()
if msg.remove and has_pin: # removing pin if msg.remove and has_pin: # removing pin
return require_confirm(ctx, Text( text = Text('Remove PIN', ui.ICON_CONFIG)
'Remove PIN', ui.ICON_CONFIG, text.type('Do you really want to')
'Do you really want to', ui.BOLD, text.bold('remove current PIN?')
'remove current PIN?')) return require_confirm(ctx, text)
if not msg.remove and has_pin: # changing pin if not msg.remove and has_pin: # changing pin
return require_confirm(ctx, Text( text = Text('Remove PIN', ui.ICON_CONFIG)
'Change PIN', ui.ICON_CONFIG, text.type('Do you really want to')
'Do you really want to', ui.BOLD, text.bold('change current PIN?')
'change current PIN?')) return require_confirm(ctx, text)
if not msg.remove and not has_pin: # setting new pin if not msg.remove and not has_pin: # setting new pin
return require_confirm(ctx, Text( text = Text('Remove PIN', ui.ICON_CONFIG)
'Change PIN', ui.ICON_CONFIG, text.type('Do you really want to')
'Do you really want to', ui.BOLD, text.bold('set new PIN?')
'set new PIN?')) return require_confirm(ctx, text)
async def request_pin_confirm(ctx, *args, **kwargs): async def request_pin_confirm(ctx, *args, **kwargs):
@ -79,11 +79,9 @@ async def request_pin_ack(ctx, *args, **kwargs):
@ui.layout @ui.layout
async def pin_mismatch(): async def pin_mismatch():
text = Text( text = Text('PIN mismatch', ui.ICON_WRONG, icon_color=ui.RED)
'PIN mismatch', ui.ICON_WRONG, text.type('Entered PINs do not', 'match each other.')
'Entered PINs do not', text.type('')
'match each other.', text.type('Please, try again...')
'',
'Please, try again...', icon_color=ui.RED)
text.render() text.render()
await loop.sleep(3 * 1000 * 1000) await loop.sleep(3 * 1000 * 1000)

View File

@ -18,10 +18,10 @@ async def load_device(ctx, msg):
if not msg.skip_checksum and not bip39.check(msg.mnemonic): if not msg.skip_checksum and not bip39.check(msg.mnemonic):
raise wire.ProcessError('Mnemonic is not valid') raise wire.ProcessError('Mnemonic is not valid')
await require_confirm(ctx, Text( text = Text('Loading seed', ui.ICON_DEFAULT)
'Loading seed', ui.ICON_DEFAULT, text.bold('Loading private seed', 'is not recommended.')
ui.BOLD, 'Loading private seed', 'is not recommended.', text.type('Continue only if you', 'know what you are doing!')
ui.NORMAL, 'Continue only if you', 'know what you are doing!')) await require_confirm(ctx, text)
storage.load_mnemonic( storage.load_mnemonic(
mnemonic=msg.mnemonic, needs_backup=True) mnemonic=msg.mnemonic, needs_backup=True)

View File

@ -61,9 +61,9 @@ async def recovery_device(ctx, msg):
async def request_wordcount(ctx): async def request_wordcount(ctx):
await ctx.call(ButtonRequest(code=MnemonicWordCount), ButtonAck) await ctx.call(ButtonRequest(code=MnemonicWordCount), ButtonAck)
content = Text('Device recovery', ui.ICON_RECOVERY, 'Number of words?') text = Text('Device recovery', ui.ICON_RECOVERY)
select = WordSelector(content) text.type('Number of words?')
count = await ctx.wait(select) count = await ctx.wait(WordSelector(text))
return count return count

View File

@ -88,56 +88,57 @@ def generate_mnemonic(strength: int,
async def show_warning(ctx): async def show_warning(ctx):
content = Text( text = Text('Backup your seed', ui.ICON_NOCOPY)
'Backup your seed', ui.ICON_NOCOPY, text.type(
'Never make a digital', 'Never make a digital',
'copy of your recovery', 'copy of your recovery',
'seed and never upload', 'seed and never upload',
'it online!') 'it online!')
await require_confirm( await require_confirm(
ctx, ctx,
content, text,
ButtonRequestType.ResetDevice, ButtonRequestType.ResetDevice,
confirm='I understand', confirm='I understand',
cancel=None) cancel=None)
async def show_wrong_entry(ctx): async def show_wrong_entry(ctx):
content = Text( text = Text('Wrong entry!', ui.ICON_WRONG, icon_color=ui.RED)
'Wrong entry!', ui.ICON_WRONG, text.type(
'You have entered', 'You have entered',
'wrong seed word.', 'wrong seed word.',
'Please check again.', icon_color=ui.RED) 'Please check again.')
await require_confirm( await require_confirm(
ctx, ctx,
content, text,
ButtonRequestType.ResetDevice, ButtonRequestType.ResetDevice,
confirm='Check again', confirm='Check again',
cancel=None) cancel=None)
async def show_success(ctx): async def show_success(ctx):
content = Text( text = Text('Backup is done!', ui.ICON_CONFIRM, icon_color=ui.GREEN)
'Backup is done!', ui.ICON_CONFIRM, text.type(
'Never make a digital', 'Never make a digital',
'copy of your recovery', 'copy of your recovery',
'seed and never upload', 'seed and never upload',
'it online!', icon_color=ui.GREEN) 'it online!')
await require_confirm( await require_confirm(
ctx, ctx,
content, text,
ButtonRequestType.ResetDevice, ButtonRequestType.ResetDevice,
confirm='Finish setup', confirm='Finish setup',
cancel=None) cancel=None)
async def show_entropy(ctx, entropy: bytes): async def show_entropy(ctx, entropy: bytes):
estr = hexlify(entropy).decode() entropy_str = hexlify(entropy).decode()
lines = chunks(estr, 16) lines = chunks(entropy_str, 16)
content = Text('Internal entropy', ui.ICON_RESET, ui.MONO, *lines) text = Text('Internal entropy', ui.ICON_RESET)
text.mono(*lines)
await require_confirm( await require_confirm(
ctx, ctx,
content, text,
ButtonRequestType.ResetDevice) ButtonRequestType.ResetDevice)
@ -158,8 +159,9 @@ async def show_mnemonic_page(page: int, page_count: int, pages: list):
debug.reset_current_words = [word for _, word in pages[page]] debug.reset_current_words = [word for _, word in pages[page]]
lines = ['%2d. %s' % (wi + 1, word) for wi, word in pages[page]] lines = ['%2d. %s' % (wi + 1, word) for wi, word in pages[page]]
content = Text('Recovery seed', ui.ICON_RESET, ui.MONO, *lines) text = Text('Recovery seed', ui.ICON_RESET)
content = Scrollpage(content, page, page_count) text.mono(*lines)
content = Scrollpage(text, page, page_count)
if page + 1 == page_count: if page + 1 == page_count:
await HoldToConfirmDialog(content) await HoldToConfirmDialog(content)

View File

@ -10,12 +10,10 @@ async def set_u2f_counter(ctx, msg):
if msg.u2f_counter is None: if msg.u2f_counter is None:
raise wire.ProcessError('No value provided') raise wire.ProcessError('No value provided')
await require_confirm(ctx, Text( text = Text('Set U2F counter', ui.ICON_CONFIG)
'Set U2F counter', ui.ICON_CONFIG, text.type('Do you really want to', 'set the U2F counter')
'Do you really want to', text.bold('to %d?' % msg.u2f_counter)
'set the U2F counter', await require_confirm(ctx, text, code=ButtonRequestType.ProtectCall)
ui.BOLD, 'to %d?' % msg.u2f_counter),
code=ButtonRequestType.ProtectCall)
storage.set_u2f_counter(msg.u2f_counter) storage.set_u2f_counter(msg.u2f_counter)

View File

@ -8,12 +8,11 @@ from apps.common.confirm import require_hold_to_confirm
async def wipe_device(ctx, msg): async def wipe_device(ctx, msg):
await require_hold_to_confirm(ctx, Text( text = Text('Wipe device', ui.ICON_WIPE, icon_color=ui.RED)
'Wipe device', text.type('Do you really want to', 'wipe the device?', '')
ui.ICON_WIPE, text.bold('All data will be lost.')
ui.NORMAL, 'Do you really want to', 'wipe the device?',
ui.NORMAL, '', 'All data will be lost.', await require_hold_to_confirm(ctx, text,
icon_color=ui.RED),
code=ButtonRequestType.WipeDevice, code=ButtonRequestType.WipeDevice,
button_style=ui.BTN_CANCEL, button_style=ui.BTN_CANCEL,
loader_style=ui.LDR_DANGER) loader_style=ui.LDR_DANGER)

View File

@ -30,9 +30,7 @@ async def get_address(ctx, msg):
async def _show_address(ctx, address: str, network: int): async def _show_address(ctx, address: str, network: int):
lines = split_address(address) lines = split_address(address)
content = Text( text = Text('Confirm address', ui.ICON_RECEIVE, icon_color=ui.GREEN)
'Confirm address', ui.ICON_RECEIVE, text.type('%s network' % get_network_str(network))
ui.NORMAL, '%s network' % get_network_str(network), text.mono(*lines)
ui.MONO, *lines, return await confirm(ctx, text, code=ButtonRequestType.Address, cancel='QR', cancel_style=ui.BTN_KEY)
icon_color=ui.GREEN)
return await confirm(ctx, content, code=ButtonRequestType.Address, cancel='QR', cancel_style=ui.BTN_KEY)

View File

@ -22,19 +22,18 @@ async def require_confirm_fee(ctx, action: str, fee: int):
async def require_confirm_content(ctx, headline: str, content: list): async def require_confirm_content(ctx, headline: str, content: list):
text = Text(headline, ui.ICON_SEND, *content, icon_color=ui.GREEN) text = Text(headline, ui.ICON_SEND, icon_color=ui.GREEN)
text.type(*content)
await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput) await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
async def require_confirm_final(ctx, fee: int): async def require_confirm_final(ctx, fee: int):
content = Text( text = Text('Final confirm', ui.ICON_SEND, icon_color=ui.GREEN)
'Final confirm', ui.ICON_SEND, text.type('Sign this transaction')
ui.NORMAL, 'Sign this transaction', text.bold('and pay %s XEM' % format_amount(fee, NEM_MAX_DIVISIBILITY))
ui.BOLD, 'and pay %s XEM' % format_amount(fee, NEM_MAX_DIVISIBILITY), text.type('for network fee?')
ui.NORMAL, 'for network fee?',
icon_color=ui.GREEN)
# we use SignTx, not ConfirmOutput, for compatibility with T1 # we use SignTx, not ConfirmOutput, for compatibility with T1
await require_hold_to_confirm(ctx, content, ButtonRequestType.SignTx) await require_hold_to_confirm(ctx, text, ButtonRequestType.SignTx)
def split_address(address: str): def split_address(address: str):

View File

@ -67,57 +67,68 @@ async def _show_page(page: int, page_count: int, content):
def _get_mosaic_properties(definition: NEMMosaicDefinition): def _get_mosaic_properties(definition: NEMMosaicDefinition):
properties = [] properties = []
# description
if definition.description: if definition.description:
t = Text('Confirm properties', ui.ICON_SEND, t = Text('Confirm properties', ui.ICON_SEND)
ui.BOLD, 'Description:', t.bold('Description:')
ui.NORMAL, *split_words(trim(definition.description, 70), 22)) t.type(*split_words(trim(definition.description, 70), 22))
properties.append(t) properties.append(t)
# transferable
if definition.transferable: if definition.transferable:
transferable = 'Yes' transferable = 'Yes'
else: else:
transferable = 'No' transferable = 'No'
t = Text('Confirm properties', ui.ICON_SEND, t = Text('Confirm properties', ui.ICON_SEND)
ui.BOLD, 'Transferable?', t.bold('Transferable?')
ui.NORMAL, transferable) t.type(transferable)
properties.append(t) properties.append(t)
# mutable_supply
if definition.mutable_supply: if definition.mutable_supply:
imm = 'mutable' imm = 'mutable'
else: else:
imm = 'immutable' imm = 'immutable'
if definition.supply: if definition.supply:
t = Text('Confirm properties', ui.ICON_SEND, t = Text('Confirm properties', ui.ICON_SEND)
ui.BOLD, 'Initial supply:', t.bold('Initial supply:')
ui.NORMAL, str(definition.supply), t.type(str(definition.supply), imm)
ui.NORMAL, imm)
else: else:
t = Text('Confirm properties', ui.ICON_SEND, t = Text('Confirm properties', ui.ICON_SEND)
ui.BOLD, 'Initial supply:', t.bold('Initial supply:')
ui.NORMAL, imm) t.type(imm)
properties.append(t) properties.append(t)
# levy
if definition.levy: if definition.levy:
t = Text('Confirm properties', ui.ICON_SEND,
ui.BOLD, 'Levy recipient:', t = Text('Confirm properties', ui.ICON_SEND)
ui.MONO, *split_address(definition.levy_address)) t.bold('Levy recipient:')
t.mono(*split_address(definition.levy_address))
properties.append(t) properties.append(t)
t = Text('Confirm properties', ui.ICON_SEND,
ui.BOLD, 'Levy fee:', t = Text('Confirm properties', ui.ICON_SEND)
ui.NORMAL, str(definition.fee), t.bold('Levy fee:')
ui.BOLD, 'Levy divisibility:', t.type(str(definition.fee))
ui.NORMAL, str(definition.divisibility)) t.bold('Levy divisibility:')
t.type(str(definition.divisibility))
properties.append(t) properties.append(t)
t = Text('Confirm properties', ui.ICON_SEND,
ui.BOLD, 'Levy namespace:', t = Text('Confirm properties', ui.ICON_SEND)
ui.NORMAL, definition.levy_namespace, t.bold('Levy namespace:')
ui.BOLD, 'Levy mosaic:', t.type(definition.levy_namespace)
ui.NORMAL, definition.levy_mosaic) t.bold('Levy mosaic:')
t.type(definition.levy_mosaic)
properties.append(t) properties.append(t)
if definition.levy == NEMMosaicLevy.MosaicLevy_Absolute: if definition.levy == NEMMosaicLevy.MosaicLevy_Absolute:
levy_type = 'absolute' levy_type = 'absolute'
else: else:
levy_type = 'percentile' levy_type = 'percentile'
t = Text('Confirm properties', ui.ICON_SEND, t = Text('Confirm properties', ui.ICON_SEND)
ui.BOLD, 'Levy type:', t.bold('Levy type:')
ui.NORMAL, levy_type) t.type(levy_type)
properties.append(t) properties.append(t)
return properties return properties

View File

@ -42,8 +42,7 @@ async def ask_aggregate_modification(ctx, common: NEMTransactionCommon, mod: NEM
async def _require_confirm_address(ctx, action: str, address: str): async def _require_confirm_address(ctx, action: str, address: str):
content = Text('Confirm address', ui.ICON_SEND, text = Text('Confirm address', ui.ICON_SEND, icon_color=ui.GREEN)
ui.NORMAL, action, text.type(action)
ui.MONO, *split_address(address), text.mono(*split_address(address))
icon_color=ui.GREEN) await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
await require_confirm(ctx, content, ButtonRequestType.ConfirmOutput)

View File

@ -30,38 +30,31 @@ async def ask_transfer_mosaic(ctx, common: NEMTransactionCommon, transfer: NEMTr
mosaic_quantity = mosaic.quantity * transfer.amount / NEM_MOSAIC_AMOUNT_DIVISOR mosaic_quantity = mosaic.quantity * transfer.amount / NEM_MOSAIC_AMOUNT_DIVISOR
if definition: if definition:
msg = Text('Confirm mosaic', ui.ICON_SEND, msg = Text('Confirm mosaic', ui.ICON_SEND, icon_color=ui.GREEN)
'Confirm transfer of', msg.type('Confirm transfer of')
ui.BOLD, format_amount(mosaic_quantity, definition['divisibility']) + definition['ticker'], msg.bold(format_amount(mosaic_quantity, definition['divisibility']) + definition['ticker'])
ui.NORMAL, 'of', msg.type('of')
ui.BOLD, definition['name'], msg.bold(definition['name'])
icon_color=ui.GREEN)
await require_confirm(ctx, msg, ButtonRequestType.ConfirmOutput) await require_confirm(ctx, msg, ButtonRequestType.ConfirmOutput)
if 'levy' in definition and 'fee' in definition: if 'levy' in definition and 'fee' in definition:
levy_msg = _get_levy_msg(definition, mosaic_quantity, common.network) levy_msg = _get_levy_msg(definition, mosaic_quantity, common.network)
msg = Text('Confirm mosaic', ui.ICON_SEND, msg = Text('Confirm mosaic', ui.ICON_SEND, icon_color=ui.GREEN)
'Confirm mosaic', msg.type('Confirm mosaic', 'levy fee of')
'levy fee of', msg.bold(levy_msg)
ui.BOLD, levy_msg,
icon_color=ui.GREEN)
await require_confirm(ctx, msg, ButtonRequestType.ConfirmOutput) await require_confirm(ctx, msg, ButtonRequestType.ConfirmOutput)
else: else:
msg = Text('Confirm mosaic', ui.ICON_SEND, msg = Text('Confirm mosaic', ui.ICON_SEND, icon_color=ui.RED)
ui.BOLD, 'Unknown mosaic!', msg.bold('Unknown mosaic!')
ui.NORMAL, *split_words('Divisibility and levy cannot be shown for unknown mosaics', 22), msg.type(*split_words('Divisibility and levy cannot be shown for unknown mosaics', 22))
icon_color=ui.RED)
await require_confirm(ctx, msg, ButtonRequestType.ConfirmOutput) await require_confirm(ctx, msg, ButtonRequestType.ConfirmOutput)
msg = Text('Confirm mosaic', ui.ICON_SEND, msg = Text('Confirm mosaic', ui.ICON_SEND, icon_color=ui.GREEN)
ui.NORMAL, 'Confirm transfer of', msg.type('Confirm transfer of')
ui.BOLD, '%s raw units' % mosaic_quantity, msg.bold('%s raw units' % mosaic_quantity)
ui.NORMAL, 'of', msg.type('of')
ui.BOLD, '%s.%s' % (mosaic.namespace, mosaic.mosaic), msg.bold('%s.%s' % (mosaic.namespace, mosaic.mosaic))
icon_color=ui.GREEN)
await require_confirm(ctx, msg, ButtonRequestType.ConfirmOutput) await require_confirm(ctx, msg, ButtonRequestType.ConfirmOutput)
@ -102,12 +95,11 @@ async def ask_importance_transfer(ctx, common: NEMTransactionCommon, imp: NEMImp
async def _require_confirm_transfer(ctx, recipient, value): async def _require_confirm_transfer(ctx, recipient, value):
content = Text('Confirm transfer', ui.ICON_SEND, text = Text('Confirm transfer', ui.ICON_SEND, icon_color=ui.GREEN)
ui.BOLD, 'Send %s XEM' % format_amount(value, NEM_MAX_DIVISIBILITY), text.bold('Send %s XEM' % format_amount(value, NEM_MAX_DIVISIBILITY))
ui.NORMAL, 'to', text.type('to')
ui.MONO, *split_address(recipient), text.mono(*split_address(recipient))
icon_color=ui.GREEN) await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
await require_confirm(ctx, content, ButtonRequestType.ConfirmOutput)
async def _require_confirm_payload(ctx, payload: bytes, encrypt=False): async def _require_confirm_payload(ctx, payload: bytes, encrypt=False):
@ -116,13 +108,11 @@ async def _require_confirm_payload(ctx, payload: bytes, encrypt=False):
if len(payload) > 48: if len(payload) > 48:
payload = payload[:48] + '..' payload = payload[:48] + '..'
if encrypt: if encrypt:
content = Text('Confirm payload', ui.ICON_SEND, text = Text('Confirm payload', ui.ICON_SEND, icon_color=ui.GREEN)
ui.BOLD, 'Encrypted:', text.bold('Encrypted:')
ui.NORMAL, *split_words(payload, 22), text.type(*split_words(payload, 22))
icon_color=ui.GREEN)
else: else:
content = Text('Confirm payload', ui.ICON_SEND, text = Text('Confirm payload', ui.ICON_SEND, icon_color=ui.RED)
ui.BOLD, 'Unencrypted:', text.bold('Unencrypted:')
ui.NORMAL, *split_words(payload, 22), text.type(*split_words(payload, 22))
icon_color=ui.RED) await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
await require_confirm(ctx, content, ButtonRequestType.ConfirmOutput)

View File

@ -20,8 +20,9 @@ async def cipher_key_value(ctx, msg):
title = 'Encrypt value' title = 'Encrypt value'
else: else:
title = 'Decrypt value' title = 'Decrypt value'
lines = split_words(msg.key, ui.WIDTH - 2 * TEXT_MARGIN_LEFT, metric=lambda x: ui.display.text_width(x, ui.NORMAL)) text = Text(title, ui.ICON_DEFAULT)
await require_confirm(ctx, Text(title, ui.ICON_DEFAULT, max_lines=5, *lines)) text.type(msg.key)
await require_confirm(ctx, text)
node = await seed.derive_node(ctx, msg.address_n) node = await seed.derive_node(ctx, msg.address_n)
value = compute_cipher_key_value(msg, node.private_key()) value = compute_cipher_key_value(msg, node.private_key())

View File

@ -30,9 +30,9 @@ async def get_ecdh_session_key(ctx, msg):
async def require_confirm_ecdh_session_key(ctx, identity): async def require_confirm_ecdh_session_key(ctx, identity):
lines = chunks(serialize_identity_without_proto(identity), 18) lines = chunks(serialize_identity_without_proto(identity), 18)
proto = identity.proto.upper() if identity.proto else 'identity' proto = identity.proto.upper() if identity.proto else 'identity'
header = 'Decrypt %s' % (proto,) text = Text('Decrypt %s' % proto, ui.ICON_DEFAULT)
content = Text(header, ui.ICON_DEFAULT, ui.MONO, *lines, max_lines=5) text.mono(*lines)
await require_confirm(ctx, content) await require_confirm(ctx, text)
def get_ecdh_path(identity: str, index: int): def get_ecdh_path(identity: str, index: int):

View File

@ -8,11 +8,10 @@ from apps.common.confirm import require_confirm
async def get_entropy(ctx, msg): async def get_entropy(ctx, msg):
await require_confirm(ctx, Text( text = Text('Confirm entropy', ui.ICON_DEFAULT)
'Confirm entropy', ui.ICON_DEFAULT, text.bold('Do you really want', 'to send entropy?')
ui.BOLD, 'Do you really want', 'to send entropy?', text.type('Continue only if you', 'know what you are doing!')
ui.NORMAL, 'Continue only if you', 'know what you are doing!'), await require_confirm(ctx, text, code=ButtonRequestType.ProtectCall)
code=ButtonRequestType.ProtectCall)
size = min(msg.size, 1024) size = min(msg.size, 1024)
entropy = random.bytes(size) entropy = random.bytes(size)

View File

@ -38,8 +38,9 @@ async def get_public_key(ctx, msg):
async def _show_pubkey(ctx, pubkey: bytes): async def _show_pubkey(ctx, pubkey: bytes):
lines = chunks(hexlify(pubkey).decode(), 18) lines = chunks(hexlify(pubkey).decode(), 18)
content = Text('Confirm public key', ui.ICON_RECEIVE, ui.MONO, *lines, icon_color=ui.GREEN) text = Text('Confirm public key', ui.ICON_RECEIVE, icon_color=ui.GREEN)
text.mono(*lines)
return await require_confirm( return await require_confirm(
ctx, ctx,
content, text,
code=ButtonRequestType.PublicKey) code=ButtonRequestType.PublicKey)

View File

@ -53,9 +53,9 @@ async def require_confirm_sign_identity(ctx, identity, challenge_visual):
lines.extend(chunks(serialize_identity_without_proto(identity), 18)) lines.extend(chunks(serialize_identity_without_proto(identity), 18))
proto = identity.proto.upper() if identity.proto else 'identity' proto = identity.proto.upper() if identity.proto else 'identity'
header = 'Sign %s' % proto text = Text('Sign %s' % proto, ui.ICON_DEFAULT)
content = Text(header, ui.ICON_DEFAULT, *lines, max_lines=5) text.type(*lines)
await require_confirm(ctx, content) await require_confirm(ctx, text)
def serialize_identity(identity): def serialize_identity(identity):

View File

@ -39,5 +39,6 @@ async def sign_message(ctx, msg):
async def require_confirm_sign_message(ctx, message): async def require_confirm_sign_message(ctx, message):
message = split_message(message) message = split_message(message)
content = Text('Sign message', ui.ICON_DEFAULT, max_lines=5, *message) text = Text('Sign message', ui.ICON_DEFAULT)
await require_confirm(ctx, content) text.type(*message)
await require_confirm(ctx, text)

View File

@ -26,40 +26,38 @@ async def confirm_output(ctx, output, coin):
data = hexlify(output.op_return_data).decode() data = hexlify(output.op_return_data).decode()
if len(data) >= 18 * 5: if len(data) >= 18 * 5:
data = data[:(18 * 5 - 3)] + '...' data = data[:(18 * 5 - 3)] + '...'
content = Text('OP_RETURN', ui.ICON_SEND, text = Text('OP_RETURN', ui.ICON_SEND, icon_color=ui.GREEN)
ui.MONO, *split_op_return(data), icon_color=ui.GREEN) text.mono(*split_op_return(data))
else: else:
address = output.address address = output.address
address_short = addresses.address_short(coin, address) address_short = addresses.address_short(coin, address)
content = Text('Confirm sending', ui.ICON_SEND, text = Text('Confirm sending', ui.ICON_SEND, icon_color=ui.GREEN)
ui.NORMAL, format_coin_amount(output.amount, coin) + ' to', text.type(format_coin_amount(output.amount, coin) + ' to')
ui.MONO, *split_address(address_short), icon_color=ui.GREEN) text.mono(*split_address(address_short))
return await confirm(ctx, content, ButtonRequestType.ConfirmOutput) return await confirm(ctx, text, ButtonRequestType.ConfirmOutput)
async def confirm_total(ctx, spending, fee, coin): async def confirm_total(ctx, spending, fee, coin):
content = Text('Confirm transaction', ui.ICON_SEND, text = Text('Confirm transaction', ui.ICON_SEND, icon_color=ui.GREEN)
'Total amount:', text.type('Total amount:')
ui.BOLD, format_coin_amount(spending, coin), text.bold(format_coin_amount(spending, coin))
ui.NORMAL, 'including fee:', text.type('including fee:')
ui.BOLD, format_coin_amount(fee, coin), icon_color=ui.GREEN) text.bold(format_coin_amount(fee, coin))
return await hold_to_confirm(ctx, content, ButtonRequestType.SignTx) return await hold_to_confirm(ctx, text, ButtonRequestType.SignTx)
async def confirm_feeoverthreshold(ctx, fee, coin): async def confirm_feeoverthreshold(ctx, fee, coin):
content = Text('High fee', ui.ICON_SEND, text = Text('High fee', ui.ICON_SEND, icon_color=ui.GREEN)
'The fee of', text.type('The fee of')
ui.BOLD, format_coin_amount(fee, coin), text.bold(format_coin_amount(fee, coin))
ui.NORMAL, 'is unexpectedly high.', text.type('is unexpectedly high.', 'Continue?')
'Continue?', icon_color=ui.GREEN) return await confirm(ctx, text, ButtonRequestType.FeeOverThreshold)
return await confirm(ctx, content, ButtonRequestType.FeeOverThreshold)
async def confirm_foreign_address(ctx, address_n, coin): async def confirm_foreign_address(ctx, address_n, coin):
content = Text('Confirm sending', ui.ICON_SEND, text = Text('Confirm sending', ui.ICON_SEND, icon_color=ui.RED)
'Trying to spend', text.type(
'coins from another chain.', 'Trying to spend',
'Continue?', icon_color=ui.RED) 'coins from another chain.',
'Continue?')
return await confirm(ctx, content, ButtonRequestType.SignTx) return await confirm(ctx, text, ButtonRequestType.SignTx)

View File

@ -57,10 +57,10 @@ async def verify_message(ctx, msg):
async def require_confirm_verify_message(ctx, address, message): async def require_confirm_verify_message(ctx, address, message):
lines = split_address(address) text = Text('Confirm address', ui.ICON_DEFAULT)
content = Text('Confirm address', ui.ICON_DEFAULT, ui.MONO, *lines) text.mono(*split_address(address))
await require_confirm(ctx, content) await require_confirm(ctx, text)
message = split_message(message) text = Text('Verify message', ui.ICON_DEFAULT)
content = Text('Verify message', ui.ICON_DEFAULT, max_lines=5, *message) text.type(*split_message(message))
await require_confirm(ctx, content) await require_confirm(ctx, text)