from threading import Thread from asciimatics.exceptions import NextScene from asciimatics.widgets import Frame, Layout, Button, Divider, Label from ..operation_strings import descriptions as op_desc from ..utils import generic_handle_stream_response from .TUIStreamResponseHandler import TUIStreamResponseHandler class TransactionView(Frame): def __init__(self, screen, width, height, model): super().__init__( screen, height, width, can_scroll=False, on_load=self._txnview_on_load, title='Running Transaction', ) self._model = model # map operation names to label widgets self._labels = model.viewdata['Transaction']['labels'] # this is an ugly hack to get around the fact that _on_load() # will be called again when we reset() in enable_next_btn. self._loaded = False def _add_buttons(self): layout = Layout([100]) self.add_layout(layout) layout.add_widget(Divider()) layout = Layout([1, 1]) self.add_layout(layout) self._next_btn = Button('Next', self._next) # we don't want to disable the button if the txn completed # and the user just resized the window if self._model.viewdata['Transaction']['status'] != 'completed': self._next_btn.disabled = True layout.add_widget(self._next_btn, 1) def _add_blank_line(self): self._op_layout.add_widget(Label(''), 0) self._op_layout.add_widget(Label(''), 2) def _txnview_on_load(self): if self._loaded: return self._loaded = True d = self._model.viewdata['Transaction'] first_time = True if d['op_layout'] is None: self._op_layout = Layout([12, 1, 10]) self.add_layout(self._op_layout) # store the layouts so that we can re-use them when the screen # gets resized d['op_layout'] = self._op_layout for _ in range(2): self._add_blank_line() for operation in self._model.operations: desc = op_desc[operation] self._op_layout.add_widget(Label(desc + '...', align='>'), 0) desc_label = Label('', align='<') self._op_layout.add_widget(desc_label, 2) self._labels[operation] = desc_label self._add_blank_line() # this is the where success/failure messages etc. get placed self._msg_layout = Layout([100]) self.add_layout(self._msg_layout) d['msg_layout'] = self._msg_layout else: # we arrive here when the screen has been resized first_time = False # restore the layouts which we saved self._op_layout = d['op_layout'] self.add_layout(self._op_layout) self._msg_layout = d['msg_layout'] self.add_layout(self._msg_layout) # fill up the rest of the space self.add_layout(Layout([100], fill_frame=True)) self._add_buttons() self.fix() # only send the API request the first time we arrive at this # scene, not when the screen gets resized if first_time: Thread(target=self._do_txn).start() def _do_txn(self): self._model.viewdata['Transaction']['status'] = 'in progress' resp = self._model.deferred_req() handler = TUIStreamResponseHandler( model=self._model, labels=self._labels, msg_layout=self._msg_layout, txn_view=self, ) generic_handle_stream_response(resp, self._model.operations, handler) def enable_next_btn(self): self._next_btn.disabled = False # If we don't reset, the button isn't selectable, even though we # enabled it self.reset() # save the fact that the transaction is completed self._model.viewdata['Transaction']['status'] = 'completed' def _next(self): self._model.reset() raise NextScene('Welcome')