kivy tx dialog: abstract away ActionDropdown, mv into its own file
This commit is contained in:
70
electrum/gui/kivy/uix/actiondropdown.py
Normal file
70
electrum/gui/kivy/uix/actiondropdown.py
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
from typing import NamedTuple, Callable, Sequence
|
||||||
|
|
||||||
|
from kivy.uix.dropdown import DropDown
|
||||||
|
from kivy.uix.button import Button
|
||||||
|
|
||||||
|
from electrum.gui.kivy.i18n import _
|
||||||
|
|
||||||
|
|
||||||
|
class ActionButtonOption(NamedTuple):
|
||||||
|
text: str
|
||||||
|
func: Callable[['Button'], None]
|
||||||
|
enabled: bool = True
|
||||||
|
|
||||||
|
|
||||||
|
class ActionDropdown(Button):
|
||||||
|
"""A button that offers a list of actions and can expand into a dropdown.
|
||||||
|
|
||||||
|
If the list of available actions:
|
||||||
|
- is empty, the button will be hidden,
|
||||||
|
- consists of a single option, the button will correspond to that,
|
||||||
|
- consists of multiple options, the button opens a dropdown which has one sub-button for each.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
Button.__init__(
|
||||||
|
self,
|
||||||
|
text='',
|
||||||
|
disabled=True,
|
||||||
|
opacity=0,
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
|
self.dropdown_text = _('Options')
|
||||||
|
self._on_release = None
|
||||||
|
|
||||||
|
def update(self, *, options: Sequence[ActionButtonOption] = ()):
|
||||||
|
num_options = sum(map(lambda o: bool(o.enabled), options))
|
||||||
|
# if no options available, hide button
|
||||||
|
if num_options == 0:
|
||||||
|
self.disabled = True
|
||||||
|
self.opacity = 0
|
||||||
|
return
|
||||||
|
self.disabled = False
|
||||||
|
self.opacity = 1
|
||||||
|
|
||||||
|
if num_options == 1:
|
||||||
|
# only one option, button will correspond to that
|
||||||
|
for option in options:
|
||||||
|
if option.enabled:
|
||||||
|
self.text = option.text
|
||||||
|
self._on_release = option.func
|
||||||
|
else:
|
||||||
|
# multiple options. button opens dropdown which has one sub-button for each
|
||||||
|
dropdown = DropDown()
|
||||||
|
self.text = self.dropdown_text
|
||||||
|
self._on_release = dropdown.open
|
||||||
|
for option in options:
|
||||||
|
if option.enabled:
|
||||||
|
btn = Button(
|
||||||
|
text=option.text,
|
||||||
|
size_hint_y=None,
|
||||||
|
height=self.height,
|
||||||
|
halign='center',
|
||||||
|
valign='center',
|
||||||
|
)
|
||||||
|
btn.bind(on_release=option.func)
|
||||||
|
dropdown.add_widget(btn)
|
||||||
|
|
||||||
|
def on_release(self):
|
||||||
|
if self._on_release:
|
||||||
|
self._on_release(self)
|
||||||
@@ -12,15 +12,16 @@ from kivy.uix.label import Label
|
|||||||
from kivy.uix.dropdown import DropDown
|
from kivy.uix.dropdown import DropDown
|
||||||
from kivy.uix.button import Button
|
from kivy.uix.button import Button
|
||||||
|
|
||||||
from .question import Question
|
|
||||||
from electrum.gui.kivy.i18n import _
|
|
||||||
|
|
||||||
from electrum.util import InvalidPassword
|
from electrum.util import InvalidPassword
|
||||||
from electrum.address_synchronizer import TX_HEIGHT_LOCAL
|
from electrum.address_synchronizer import TX_HEIGHT_LOCAL
|
||||||
from electrum.wallet import CannotBumpFee, CannotDoubleSpendTx
|
from electrum.wallet import CannotBumpFee, CannotDoubleSpendTx
|
||||||
from electrum.transaction import Transaction, PartialTransaction
|
from electrum.transaction import Transaction, PartialTransaction
|
||||||
from electrum.network import NetworkException
|
from electrum.network import NetworkException
|
||||||
from ...util import address_colors
|
|
||||||
|
from electrum.gui.kivy.i18n import _
|
||||||
|
from electrum.gui.kivy.util import address_colors
|
||||||
|
from ..actiondropdown import ActionDropdown, ActionButtonOption
|
||||||
|
from .question import Question
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from ...main_window import ElectrumWindow
|
from ...main_window import ElectrumWindow
|
||||||
@@ -94,14 +95,10 @@ Builder.load_string('''
|
|||||||
BoxLayout:
|
BoxLayout:
|
||||||
size_hint: 1, None
|
size_hint: 1, None
|
||||||
height: '48dp'
|
height: '48dp'
|
||||||
Button:
|
ActionDropdown:
|
||||||
id: action_button
|
id: action_dropdown
|
||||||
size_hint: 0.5, None
|
size_hint: 0.5, None
|
||||||
height: '48dp'
|
height: '48dp'
|
||||||
text: ''
|
|
||||||
disabled: True
|
|
||||||
opacity: 0
|
|
||||||
on_release: root.on_action_button_clicked()
|
|
||||||
IconButton:
|
IconButton:
|
||||||
size_hint: 0.5, None
|
size_hint: 0.5, None
|
||||||
height: '48dp'
|
height: '48dp'
|
||||||
@@ -120,12 +117,6 @@ Builder.load_string('''
|
|||||||
''')
|
''')
|
||||||
|
|
||||||
|
|
||||||
class ActionButtonOption(NamedTuple):
|
|
||||||
text: str
|
|
||||||
func: Callable
|
|
||||||
enabled: bool
|
|
||||||
|
|
||||||
|
|
||||||
class TxDialog(Factory.Popup):
|
class TxDialog(Factory.Popup):
|
||||||
|
|
||||||
def __init__(self, app, tx):
|
def __init__(self, app, tx):
|
||||||
@@ -133,7 +124,6 @@ class TxDialog(Factory.Popup):
|
|||||||
self.app = app # type: ElectrumWindow
|
self.app = app # type: ElectrumWindow
|
||||||
self.wallet = self.app.wallet
|
self.wallet = self.app.wallet
|
||||||
self.tx = tx # type: Transaction
|
self.tx = tx # type: Transaction
|
||||||
self._action_button_fn = lambda btn: None
|
|
||||||
|
|
||||||
# If the wallet can populate the inputs with more info, do it now.
|
# If the wallet can populate the inputs with more info, do it now.
|
||||||
# As a result, e.g. we might learn an imported address tx is segwit,
|
# As a result, e.g. we might learn an imported address tx is segwit,
|
||||||
@@ -193,10 +183,10 @@ class TxDialog(Factory.Popup):
|
|||||||
dict_entry['color'], dict_entry['background_color'] = address_colors(self.wallet, dict_entry['address'])
|
dict_entry['color'], dict_entry['background_color'] = address_colors(self.wallet, dict_entry['address'])
|
||||||
|
|
||||||
self.can_remove_tx = tx_details.can_remove
|
self.can_remove_tx = tx_details.can_remove
|
||||||
self.update_action_button()
|
self.update_action_dropdown()
|
||||||
|
|
||||||
def update_action_button(self):
|
def update_action_dropdown(self):
|
||||||
action_button = self.ids.action_button
|
action_dropdown = self.ids.action_dropdown # type: ActionDropdown
|
||||||
# note: button texts need to be short; there is only horizontal space for ~13 chars
|
# note: button texts need to be short; there is only horizontal space for ~13 chars
|
||||||
options = (
|
options = (
|
||||||
ActionButtonOption(text=_('Sign'), func=lambda btn: self.do_sign(), enabled=self.can_sign),
|
ActionButtonOption(text=_('Sign'), func=lambda btn: self.do_sign(), enabled=self.can_sign),
|
||||||
@@ -205,41 +195,7 @@ class TxDialog(Factory.Popup):
|
|||||||
ActionButtonOption(text=_('Cancel') + '\n(double-spend)', func=lambda btn: self.do_dscancel(), enabled=self.can_dscancel),
|
ActionButtonOption(text=_('Cancel') + '\n(double-spend)', func=lambda btn: self.do_dscancel(), enabled=self.can_dscancel),
|
||||||
ActionButtonOption(text=_('Remove'), func=lambda btn: self.remove_local_tx(), enabled=self.can_remove_tx),
|
ActionButtonOption(text=_('Remove'), func=lambda btn: self.remove_local_tx(), enabled=self.can_remove_tx),
|
||||||
)
|
)
|
||||||
num_options = sum(map(lambda o: bool(o.enabled), options))
|
action_dropdown.update(options=options)
|
||||||
# if no options available, hide button
|
|
||||||
if num_options == 0:
|
|
||||||
action_button.disabled = True
|
|
||||||
action_button.opacity = 0
|
|
||||||
return
|
|
||||||
action_button.disabled = False
|
|
||||||
action_button.opacity = 1
|
|
||||||
|
|
||||||
if num_options == 1:
|
|
||||||
# only one option, button will correspond to that
|
|
||||||
for option in options:
|
|
||||||
if option.enabled:
|
|
||||||
action_button.text = option.text
|
|
||||||
self._action_button_fn = option.func
|
|
||||||
else:
|
|
||||||
# multiple options. button opens dropdown which has one sub-button for each
|
|
||||||
dropdown = DropDown()
|
|
||||||
action_button.text = _('Options')
|
|
||||||
self._action_button_fn = dropdown.open
|
|
||||||
for option in options:
|
|
||||||
if option.enabled:
|
|
||||||
btn = Button(
|
|
||||||
text=option.text,
|
|
||||||
size_hint_y=None,
|
|
||||||
height='48dp',
|
|
||||||
halign='center',
|
|
||||||
valign='center',
|
|
||||||
)
|
|
||||||
btn.bind(on_release=option.func)
|
|
||||||
dropdown.add_widget(btn)
|
|
||||||
|
|
||||||
def on_action_button_clicked(self):
|
|
||||||
action_button = self.ids.action_button
|
|
||||||
self._action_button_fn(action_button)
|
|
||||||
|
|
||||||
def _add_info_to_tx_from_wallet_and_network(self, tx: PartialTransaction) -> bool:
|
def _add_info_to_tx_from_wallet_and_network(self, tx: PartialTransaction) -> bool:
|
||||||
"""Returns whether successful."""
|
"""Returns whether successful."""
|
||||||
|
|||||||
Reference in New Issue
Block a user