From 0c0a8626adbe2ede60cf8e4cd13f32f3bbefe6f4 Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Mon, 26 Jan 2026 10:56:21 +0000 Subject: [PATCH] proto.xmr.tw.view: new `get_label_from_user()`, `choose_wallet()` methods --- mmgen/proto/xmr/tw/addresses.py | 32 ++++++++------------------------ mmgen/proto/xmr/tw/view.py | 28 ++++++++++++++++++++++++++++ mmgen/ui.py | 10 ++++++++-- test/cmdtest_d/xmr_autosign.py | 2 +- 4 files changed, 45 insertions(+), 27 deletions(-) diff --git a/mmgen/proto/xmr/tw/addresses.py b/mmgen/proto/xmr/tw/addresses.py index c9734f23..562464ff 100755 --- a/mmgen/proto/xmr/tw/addresses.py +++ b/mmgen/proto/xmr/tw/addresses.py @@ -17,13 +17,9 @@ from ....tw.addresses import TwAddresses from .view import MoneroTwView async def add_new_address(parent, spec, ok_msg): - from ....ui import line_input, keypress_confirm from ....color import green, yellow from ....xmrwallet import op as xmrwallet_op - lbl = line_input( - parent.cfg, - 'Enter label text for new address (or ENTER for default label): ') - add_timestr = keypress_confirm(parent.cfg, 'Add timestamp to label?') + lbl, add_timestr = parent.get_label_from_user() op = xmrwallet_op( 'new', parent.cfg, @@ -70,25 +66,13 @@ class MoneroTwAddresses(MoneroTwView, TwAddresses): class action(MoneroTwView.action): async def a_acct_new(self, parent): - from ....obj import Int - from ....util import suf - from ....addr import MMGenID - from ....ui import item_chooser - def wallet_id(wnum): - return MMGenID(proto=parent.proto, id_str='{}:M:{}'.format(parent.sid, wnum)) - res = item_chooser( - parent.cfg, - 'Choose a wallet to add a new account to', - [(d['wallet_num'], len(d['data'].accts_data['subaddress_accounts'])) - for d in parent.dump_data], - lambda d: '{a} [{b} account{c}]'.format( - a = wallet_id(d[0]).hl(), - b = Int(d[1]).hl(), - c = suf(d[1]))) - return await add_new_address( - parent, - str(res.item[0]), - f'New account added to wallet {wallet_id(res.item[0]).hl()}') + if res := parent.choose_wallet('Choose a wallet to add a new account to'): + return await add_new_address( + parent, + str(res.item[0]), + f'New account added to wallet {parent.make_wallet_id(res.item[0]).hl()}') + else: + return 'erase' class item_action(TwAddresses.item_action): acct_methods = ('i_addr_new') diff --git a/mmgen/proto/xmr/tw/view.py b/mmgen/proto/xmr/tw/view.py index 87bcb92c..9c6d56d0 100755 --- a/mmgen/proto/xmr/tw/view.py +++ b/mmgen/proto/xmr/tw/view.py @@ -219,6 +219,34 @@ class MoneroTwView: self.accts_data[res.idx - 1].data, is_addr_idx = True) + def get_label_from_user(self): + from ....ui import line_input, keypress_confirm + lbl = line_input( + self.cfg, + 'Enter label text for new address (or ENTER for default label): ') + add_timestr = keypress_confirm(self.cfg, 'Add timestamp to label?') + return lbl, add_timestr + + def make_wallet_id(self, wnum): + from ....addr import MMGenID + return MMGenID(proto=self.proto, id_str='{}:M:{}'.format(self.sid, wnum)) + + def choose_wallet(self, prompt): + from ....obj import Int + from ....util import msg, suf + from ....ui import item_chooser + msg('\n') + return item_chooser( + self.cfg, + prompt, + [(d['wallet_num'], len(d['data'].accts_data['subaddress_accounts'])) + for d in self.dump_data], + lambda d: '{a} [{b} account{c}]'.format( + a = self.make_wallet_id(d[0]).hl(), + b = Int(d[1]).hl(), + c = suf(d[1])), + empty_ok = True) + class action(TwView.action): async def a_sync_wallets(self, parent): diff --git a/mmgen/ui.py b/mmgen/ui.py index 7e6bbc3a..a016189b 100755 --- a/mmgen/ui.py +++ b/mmgen/ui.py @@ -117,18 +117,24 @@ def keypress_confirm( case _: msg_r('\nInvalid reply\n' if verbose else '\r') -def item_chooser(cfg, hdr, items, item_formatter, indent=' '): +def item_chooser(cfg, hdr, items, item_formatter, indent='', empty_ok=False, add_nl=False): from collections import namedtuple col1_w = len(str(len(items))) prompt = '{i}{a}:\n{i}{b}\n{i}{c}'.format( a = hdr, b = ('\n' + indent).join(f' {n:{col1_w}}) {item_formatter(d)}' for n, d in enumerate(items, 1)), - c = 'Enter a number> ', + c = 'Enter a number, or ENTER to return to main menu> ' if empty_ok else 'Enter a number> ', i = indent) while True: res = line_input(cfg, prompt) + if not res and empty_ok: + if add_nl: + msg('') + return None if is_int(res) and 0 < int(res) <= len(items): num = int(res) + if add_nl: + msg('') return namedtuple('user_choice', 'num idx item')(num, num - 1, items[num - 1]) msg(f'{indent}{res}: invalid entry\n') diff --git a/test/cmdtest_d/xmr_autosign.py b/test/cmdtest_d/xmr_autosign.py index efa75106..e4430da0 100755 --- a/test/cmdtest_d/xmr_autosign.py +++ b/test/cmdtest_d/xmr_autosign.py @@ -721,7 +721,7 @@ class CmdTestXMRCompat(CmdTestXMRAutosign): t.expect('main menu): ', str(lbl_addr_idx)) elif newacct_wallet_num: t.expect(menu_prompt, 'N') - t.expect('number> ', f'{newacct_wallet_num}\n') + t.expect('number, or ENTER to return to main menu> ', f'{newacct_wallet_num}\n') elif newaddr_acct_num: t.expect(menu_prompt, 'n') t.expect('main menu): ', str(newaddr_acct_num))