From eb04c84f264827b808d77ea2f2db4af68a0eae10 Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Sun, 11 Dec 2022 12:12:07 +0000 Subject: [PATCH] tw.view: new classes: scroll_action, sort_action, display_action --- mmgen/data/version | 2 +- mmgen/proto/btc/tw/addresses.py | 5 +- mmgen/proto/btc/tw/prune.py | 3 +- mmgen/proto/btc/tw/txhistory.py | 3 +- mmgen/proto/btc/tw/unspent.py | 5 +- mmgen/proto/eth/tw/addresses.py | 7 +- mmgen/proto/eth/tw/unspent.py | 9 +- mmgen/tw/addresses.py | 5 +- mmgen/tw/prune.py | 6 +- mmgen/tw/txhistory.py | 7 +- mmgen/tw/unspent.py | 4 +- mmgen/tw/view.py | 173 ++++++++++++++++++++------------ 12 files changed, 134 insertions(+), 95 deletions(-) diff --git a/mmgen/data/version b/mmgen/data/version index 0d81bdb2..76a62c63 100644 --- a/mmgen/data/version +++ b/mmgen/data/version @@ -1 +1 @@ -13.3.dev29 +13.3.dev30 diff --git a/mmgen/proto/btc/tw/addresses.py b/mmgen/proto/btc/tw/addresses.py index c8dc1209..cc68c16a 100755 --- a/mmgen/proto/btc/tw/addresses.py +++ b/mmgen/proto/btc/tw/addresses.py @@ -33,17 +33,16 @@ Actions: [q]uit menu, r[e]draw, add [l]abel: 'a':'s_amt', 'A':'s_age', 'M':'s_twmmid', - 'r':'d_reverse', + 'r':'s_reverse', 'D':'d_days', 'e':'d_redraw', 'E':'d_showempty', 'u':'d_showused', 'L':'d_all_labels', - 'q':'a_quit', 'v':'a_view', 'w':'a_view_detail', 'p':'a_print_detail', - 'l':'a_comment_add' } + 'l':'i_comment_add' } async def get_rpc_data(self): diff --git a/mmgen/proto/btc/tw/prune.py b/mmgen/proto/btc/tw/prune.py index 78bb054e..d778d783 100755 --- a/mmgen/proto/btc/tw/prune.py +++ b/mmgen/proto/btc/tw/prune.py @@ -28,13 +28,12 @@ Pruning: [q]uit pruning, [p]rune, [u]nprune, [c]lear prune list: 'a':'s_amt', 'A':'s_age', 'M':'s_twmmid', - 'r':'d_reverse', + 'r':'s_reverse', 'D':'d_days', 'e':'d_redraw', 'E':'d_showempty', 'U':'d_showused', 'L':'d_all_labels', - 'q':'a_quit', 'v':'a_view', 'w':'a_view_detail', 'p':'a_prune', diff --git a/mmgen/proto/btc/tw/txhistory.py b/mmgen/proto/btc/tw/txhistory.py index 653fb8d0..e55ea0fe 100755 --- a/mmgen/proto/btc/tw/txhistory.py +++ b/mmgen/proto/btc/tw/txhistory.py @@ -242,13 +242,12 @@ Filters/Actions: show [u]nconfirmed, [q]uit menu, r[e]draw: 'a':'s_amt', 'm':'s_total_amt', 't':'s_txid', - 'r':'d_reverse', + 'r':'s_reverse', 'D':'d_days', 'e':'d_redraw', 'u':'d_show_unconfirmed', 'i':'d_show_txid', 'T':'d_show_total_amt', - 'q':'a_quit', 'v':'a_view', 'V':'a_view_detail', 'p':'a_print_squeezed', diff --git a/mmgen/proto/btc/tw/unspent.py b/mmgen/proto/btc/tw/unspent.py index 1a03cb2e..669dfacf 100755 --- a/mmgen/proto/btc/tw/unspent.py +++ b/mmgen/proto/btc/tw/unspent.py @@ -40,17 +40,16 @@ Actions: [q]uit menu, [p]rint, r[e]draw, add [l]abel: 'a':'s_amt', 'd':'s_addr', 'A':'s_age', - 'r':'d_reverse', 'M':'s_twmmid', + 'r':'s_reverse', 'D':'d_days', 'o':'d_group', 'm':'d_mmid', 'e':'d_redraw', - 'q':'a_quit', 'p':'a_print_detail', 'v':'a_view', 'w':'a_view_detail', - 'l':'a_comment_add' } + 'l':'i_comment_add' } async def get_rpc_data(self): # bitcoin-cli help listunspent: diff --git a/mmgen/proto/eth/tw/addresses.py b/mmgen/proto/eth/tw/addresses.py index e3f6c002..1b722a93 100755 --- a/mmgen/proto/eth/tw/addresses.py +++ b/mmgen/proto/eth/tw/addresses.py @@ -30,13 +30,12 @@ Actions: [q]uit menu, r[e]draw, [D]elete addr, add [l]abel: key_mappings = { 'a':'s_amt', 'M':'s_twmmid', - 'r':'d_reverse', + 'r':'s_reverse', 'e':'d_redraw', 'E':'d_showempty', 'L':'d_all_labels', - 'q':'a_quit', - 'l':'a_comment_add', - 'D':'a_addr_delete', + 'l':'i_comment_add', + 'D':'i_addr_delete', 'v':'a_view', 'w':'a_view_detail', 'p':'a_print_detail' } diff --git a/mmgen/proto/eth/tw/unspent.py b/mmgen/proto/eth/tw/unspent.py index 7a0316a1..416350d6 100755 --- a/mmgen/proto/eth/tw/unspent.py +++ b/mmgen/proto/eth/tw/unspent.py @@ -54,17 +54,16 @@ Actions: [q]uit menu, [D]elete addr, add [l]abel, [R]efresh balance: key_mappings = { 'a':'s_amt', 'd':'s_addr', - 'r':'d_reverse', + 'r':'s_reverse', 'M':'s_twmmid', 'm':'d_mmid', 'e':'d_redraw', - 'q':'a_quit', 'p':'a_print_detail', 'v':'a_view', 'w':'a_view_detail', - 'l':'a_comment_add', - 'D':'a_addr_delete', - 'R':'a_balance_refresh' } + 'l':'i_comment_add', + 'D':'i_addr_delete', + 'R':'i_balance_refresh' } no_data_errmsg = 'No accounts in tracking wallet!' diff --git a/mmgen/tw/addresses.py b/mmgen/tw/addresses.py index 7ba8df7b..d730d779 100755 --- a/mmgen/tw/addresses.py +++ b/mmgen/tw/addresses.py @@ -362,10 +362,7 @@ class TwAddresses(TwView): elif False in res: return False - class action(TwView.action): - - def s_amt(self,parent): - parent.do_sort('amt') + class display_action(TwView.display_action): def d_showempty(self,parent): parent.showempty = not parent.showempty diff --git a/mmgen/tw/prune.py b/mmgen/tw/prune.py index 0c46ef17..2ada8fd0 100755 --- a/mmgen/tw/prune.py +++ b/mmgen/tw/prune.py @@ -119,7 +119,7 @@ class TwAddressesPrune(TwAddresses): else: msg('\nInvalid keypress') - def a_prune(self,parent): + async def a_prune(self,parent): def do_entry(desc,n,addrnum,e): if auto[desc]: @@ -160,13 +160,13 @@ class TwAddressesPrune(TwAddresses): if parent.scroll: msg_r(CUR_HOME + ERASE_ALL) - def a_unprune(self,parent): + async def a_unprune(self,parent): for addrnum in self.get_addrnums(parent,'unprune'): parent.disp_data[addrnum-1].tag = False if parent.scroll: msg_r(CUR_HOME + ERASE_ALL) - def a_clear_prune_list(self,parent): + async def a_clear_prune_list(self,parent): for d in parent.data: d.tag = False diff --git a/mmgen/tw/txhistory.py b/mmgen/tw/txhistory.py index f28487be..f775e495 100755 --- a/mmgen/tw/txhistory.py +++ b/mmgen/tw/txhistory.py @@ -182,7 +182,10 @@ class TwTxHistory(TwView): def dump_fn_pfx(self): return 'transaction-history' + (f'-since-block-{self.sinceblock}' if self.sinceblock else '') - class action(TwView.action): + class sort_action(TwView.sort_action): + + def s_blockheight(self,parent): + parent.do_sort('blockheight') def s_amt(self,parent): parent.do_sort('amt') @@ -192,6 +195,8 @@ class TwTxHistory(TwView): parent.do_sort('total_amt') parent.show_total_amt = True + class display_action(TwView.display_action): + def d_show_txid(self,parent): parent.show_txid = not parent.show_txid diff --git a/mmgen/tw/unspent.py b/mmgen/tw/unspent.py index 6db3beab..4ef0cc81 100755 --- a/mmgen/tw/unspent.py +++ b/mmgen/tw/unspent.py @@ -226,12 +226,14 @@ class TwUnspentOutputs(TwView): o.date = dates[idx] self.dates_set = True - class action(TwView.action): + class sort_action(TwView.sort_action): def s_twmmid(self,parent): parent.do_sort('twmmid') parent.show_mmid = True + class display_action(TwView.display_action): + def d_mmid(self,parent): parent.show_mmid = not parent.show_mmid diff --git a/mmgen/tw/view.py b/mmgen/tw/view.py index 82396f9f..bf6fd6a1 100755 --- a/mmgen/tw/view.py +++ b/mmgen/tw/view.py @@ -38,6 +38,17 @@ CUR_UP = lambda n: f'\033[{n}A' CUR_DOWN = lambda n: f'\033[{n}B' ERASE_ALL = '\033[0J' +# decorator for action.run(): +def enable_echo(orig_func): + async def f(self,parent,action_method): + if parent.scroll: + parent.term.set('echo') + ret = await orig_func(self,parent,action_method) + if parent.scroll: + parent.term.set('noecho') + return ret + return f + # base class for TwUnspentOutputs,TwAddresses,TwTxHistory: class TwView(MMGenObject,metaclass=AsyncInit): @@ -495,6 +506,14 @@ class TwView(MMGenObject,metaclass=AsyncInit): async def view_filter_and_sort(self): + action_map = { + 'a_': 'action', + 's_': 'sort_action', + 'd_': 'display_action', + 'm_': 'scroll_action', + 'i_': 'item_action', + } + def make_key_mappings(scroll): if scroll: for k in self.scroll_keys['vi']: @@ -506,6 +525,8 @@ class TwView(MMGenObject,metaclass=AsyncInit): scroll = self.scroll = g.scroll key_mappings = make_key_mappings(scroll) + action_classes = { k: getattr(self,action_map[v[:2]])() for k,v in key_mappings.items() } + action_methods = { k: getattr(v,key_mappings[k]) for k,v in action_classes.items() } prompt = self.prompt_fs.strip().format( s='\nScrolling: k=up, j=down, b=pgup, f=pgdown, g=top, G=bottom' if scroll else '' ) @@ -516,10 +537,12 @@ class TwView(MMGenObject,metaclass=AsyncInit): clear_screen = '\n\n' if opt.no_blank else CUR_HOME + ('' if scroll else ERASE_ALL) + from ..term import get_term,get_char,get_char_raw + if scroll: - term = get_term() - term.register_cleanup() - term.set('noecho') + self.term = get_term() + self.term.register_cleanup() + self.term.set('noecho') get_char = get_char_raw msg_r(CUR_HOME + ERASE_ALL) @@ -540,31 +563,18 @@ class TwView(MMGenObject,metaclass=AsyncInit): self.oneshot_msg = '' - if reply not in key_mappings: - if not scroll: - msg_r('\ninvalid keypress ') - await asyncio.sleep(0.3) - continue - - action = key_mappings[reply] - - if scroll and action.startswith('a_'): # 'a_' actions may require line input - term.set('echo') - - if hasattr(self.action,action): - if action.startswith('m_'): # scrolling actions - self.use_cached = True - await self.action().run(self,action) - elif action.startswith('s_'): # put here to allow overriding by action method - self.do_sort(action[2:]) - elif hasattr(self.item_action,action): - await self.item_action().run(self,action) - elif action == 'a_quit': + if reply in key_mappings: + ret = action_classes[reply].run(self,action_methods[reply]) + if type(ret).__name__ == 'coroutine': + await ret + elif reply == 'q': msg('') + if self.scroll: + self.term.set('echo') return self.disp_data - - if scroll and action.startswith('a_'): - term.set('noecho') + elif not scroll: + msg_r('\ninvalid keypress ') + await asyncio.sleep(0.3) @property def blank_prompt(self): @@ -581,23 +591,9 @@ class TwView(MMGenObject,metaclass=AsyncInit): class action: - async def run(self,parent,action): - ret = getattr(self,action)(parent) - if type(ret).__name__ == 'coroutine': - await ret - - def d_days(self,parent): - af = parent.age_fmts - parent.age_fmt = af[(af.index(parent.age_fmt) + 1) % len(af)] - if parent.update_widths_on_age_toggle: # TODO - pass - - def d_redraw(self,parent): - msg_r(CUR_HOME + ERASE_ALL) - - def d_reverse(self,parent): - parent.data.reverse() - parent.reverse = not parent.reverse + @enable_echo + async def run(self,parent,action_method): + return await action_method(parent) async def a_print_detail(self,parent): return await self._print(parent,output_type='detail') @@ -647,27 +643,10 @@ class TwView(MMGenObject,metaclass=AsyncInit): msg_r(CUR_HOME) do_pager( await parent.format('detail',color=True) ) - async def m_cursor_up(self,parent): - parent.pos -= min( parent.pos - 0, 1 ) - - async def m_cursor_down(self,parent): - parent.pos += min( parent.max_pos - parent.pos, 1 ) - - async def m_pg_up(self,parent): - parent.pos -= min( parent.scrollable_height, parent.pos - 0 ) - - async def m_pg_down(self,parent): - parent.pos += min( parent.scrollable_height, parent.max_pos - parent.pos ) - - async def m_top(self,parent): - parent.pos = 0 - - async def m_bot(self,parent): - parent.pos = parent.max_pos - class item_action: - async def run(self,parent,action): + @enable_echo + async def run(self,parent,action_method): if not parent.disp_data: return @@ -695,7 +674,7 @@ class TwView(MMGenObject,metaclass=AsyncInit): # None: action aborted by user or no action performed # False: an error occurred # 'redo': user will be re-prompted for item number - ret = await getattr(self,action)(parent,idx) + ret = await action_method(parent,idx) if ret != 'redo': break await asyncio.sleep(0.5) @@ -706,7 +685,7 @@ class TwView(MMGenObject,metaclass=AsyncInit): CUR_HOME + ERASE_ALL + await parent.format(display_type='squeezed',interactive=True,scroll=True) ) - async def a_balance_refresh(self,parent,idx): + async def i_balance_refresh(self,parent,idx): if not parent.keypress_confirm( f'Refreshing tracking wallet {parent.item_desc} #{idx}. Is this what you want?'): return 'redo' @@ -714,7 +693,7 @@ class TwView(MMGenObject,metaclass=AsyncInit): await parent.get_data() parent.oneshot_msg = yellow(f'{parent.proto.dcoin} balance for account #{idx} refreshed') - async def a_addr_delete(self,parent,idx): + async def i_addr_delete(self,parent,idx): if not parent.keypress_confirm( 'Removing {} {} from tracking wallet. Is this what you want?'.format( parent.item_desc, red(f'#{idx}') )): @@ -728,7 +707,7 @@ class TwView(MMGenObject,metaclass=AsyncInit): parent.oneshot_msg = red('Address could not be removed') return False - async def a_comment_add(self,parent,idx): + async def i_comment_add(self,parent,idx): async def do_comment_add(comment): @@ -766,3 +745,65 @@ class TwView(MMGenObject,metaclass=AsyncInit): return 'redo' return await do_comment_add(res) + + class scroll_action: + + def run(self,parent,action_method): + self.use_cached = True + return action_method(parent) + + def m_cursor_up(self,parent): + parent.pos -= min( parent.pos - 0, 1 ) + + def m_cursor_down(self,parent): + parent.pos += min( parent.max_pos - parent.pos, 1 ) + + def m_pg_up(self,parent): + parent.pos -= min( parent.scrollable_height, parent.pos - 0 ) + + def m_pg_down(self,parent): + parent.pos += min( parent.scrollable_height, parent.max_pos - parent.pos ) + + def m_top(self,parent): + parent.pos = 0 + + def m_bot(self,parent): + parent.pos = parent.max_pos + + class sort_action: + + def run(self,parent,action_method): + return action_method(parent) + + def s_addr(self,parent): + parent.do_sort('addr') + + def s_age(self,parent): + parent.do_sort('age') + + def s_amt(self,parent): + parent.do_sort('amt') + + def s_txid(self,parent): + parent.do_sort('txid') + + def s_twmmid(self,parent): + parent.do_sort('twmmid') + + def s_reverse(self,parent): + parent.data.reverse() + parent.reverse = not parent.reverse + + class display_action: + + def run(self,parent,action_method): + return action_method(parent) + + def d_days(self,parent): + af = parent.age_fmts + parent.age_fmt = af[(af.index(parent.age_fmt) + 1) % len(af)] + if parent.update_widths_on_age_toggle: # TODO + pass + + def d_redraw(self,parent): + msg_r(CUR_HOME + ERASE_ALL)