diff --git a/electrum/gui/kivy/main_window.py b/electrum/gui/kivy/main_window.py index 27eab521..241713eb 100644 --- a/electrum/gui/kivy/main_window.py +++ b/electrum/gui/kivy/main_window.py @@ -919,6 +919,16 @@ class ElectrumWindow(App): d = LabelDialog(_('Enter description'), text, callback) d.open() + def flodata_dialog(self, screen): + from .uix.dialogs.label_dialog import LabelDialog + text = screen.flodata + + def callback(text): + screen.flodata = text + + d = LabelDialog(_('Enter FLO data'), text, callback) + d.open() + def amount_dialog(self, screen, show_max): from .uix.dialogs.amount_dialog import AmountDialog amount = screen.amount @@ -968,6 +978,7 @@ class ElectrumWindow(App): def on_fee(self, event, *arg): self.fee_status = self.electrum_config.get_fee_status() + def protected(self, msg, f, args): if self.wallet.has_password(): on_success = lambda pw: f(*(args + (pw,))) diff --git a/electrum/gui/kivy/uix/screens.py b/electrum/gui/kivy/uix/screens.py index 73930aef..984fa2f3 100644 --- a/electrum/gui/kivy/uix/screens.py +++ b/electrum/gui/kivy/uix/screens.py @@ -184,6 +184,7 @@ class SendScreen(CScreen): self.screen.amount = self.app.format_amount_and_units(amount) if amount else '' self.payment_request = None self.screen.is_pr = False + self.screen.flodata = uri.get('flodata', '') def update(self): if self.app.wallet and self.payment_request_queued: @@ -196,6 +197,7 @@ class SendScreen(CScreen): self.screen.address = '' self.payment_request = None self.screen.is_pr = False + self.screen.flodata = '' def set_request(self, pr): self.screen.address = pr.get_requestor() @@ -260,19 +262,20 @@ class SendScreen(CScreen): outputs = [TxOutput(bitcoin.TYPE_ADDRESS, address, amount)] message = self.screen.message amount = sum(map(lambda x:x[2], outputs)) + flodata = str(self.screen.flodata) if self.app.electrum_config.get('use_rbf'): from .dialogs.question import Question - d = Question(_('Should this transaction be replaceable?'), lambda b: self._do_send(amount, message, outputs, b)) + d = Question(_('Should this transaction be replaceable?'), lambda b: self._do_send(amount, message, outputs, b, flodata)) d.open() else: - self._do_send(amount, message, outputs, False) + self._do_send(amount, message, outputs, False, flodata) - def _do_send(self, amount, message, outputs, rbf): + def _do_send(self, amount, message, outputs, rbf, flodata): # make unsigned transaction config = self.app.electrum_config coins = self.app.wallet.get_spendable_coins(None, config) try: - tx = self.app.wallet.make_unsigned_transaction(coins, outputs, config, None) + tx = self.app.wallet.make_unsigned_transaction(coins, outputs, config, None, flodata=flodata) except NotEnoughFunds: self.app.show_error(_("Not enough funds")) return diff --git a/electrum/gui/kivy/uix/ui_screens/send.kv b/electrum/gui/kivy/uix/ui_screens/send.kv index 88cbcc3a..81ef6d8f 100644 --- a/electrum/gui/kivy/uix/ui_screens/send.kv +++ b/electrum/gui/kivy/uix/ui_screens/send.kv @@ -11,6 +11,7 @@ SendScreen: address: '' amount: '' message: '' + flodata: '' is_pr: False BoxLayout padding: '12dp', '12dp', '12dp', '12dp' @@ -38,6 +39,24 @@ SendScreen: CardSeparator: opacity: int(not root.is_pr) color: blue_bottom.foreground_color + BoxLayout: + id: flodata_selection + size_hint: 1, None + height: blue_bottom.item_height + spacing: '5dp' + Image: + source: 'atlas://electrum/gui/kivy/theming/light/pen' + size_hint: None, None + size: '22dp', '22dp' + pos_hint: {'center_y': .5} + BlueButton: + id: flodata + text: s.flodata if s.flodata else (_('No FLO data') if root.is_pr else _('FLO data')) + disabled: root.is_pr + on_release: Clock.schedule_once(lambda dt: app.flodata_dialog(s)) + CardSeparator: + opacity: int(not root.is_pr) + color: blue_bottom.foreground_color BoxLayout: size_hint: 1, None height: blue_bottom.item_height diff --git a/electrum/gui/qt/main_window.py b/electrum/gui/qt/main_window.py index a80bd926..9824bf10 100644 --- a/electrum/gui/qt/main_window.py +++ b/electrum/gui/qt/main_window.py @@ -1096,16 +1096,16 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError): msg = _('This is where you write the FLO Data for the transaction') flodata_label = HelpLabel(_('FLO Data'), msg) - grid.addWidget(flodata_label, 7, 0) - self.message_tx = MyLineEdit() - grid.addWidget(self.message_tx, 7, 1, 1, -1) + grid.addWidget(flodata_label, 3, 0) + self.message_tx_e = MyLineEdit() + grid.addWidget(self.message_tx_e, 3, 1, 1, -1) self.from_label = QLabel(_('From')) - grid.addWidget(self.from_label, 3, 0) + grid.addWidget(self.from_label, 4, 0) self.from_list = MyTreeWidget(self, self.from_list_menu, ['','']) self.from_list.setHeaderHidden(True) self.from_list.setMaximumHeight(80) - grid.addWidget(self.from_list, 3, 1, 1, -1) + grid.addWidget(self.from_list, 4, 1, 1, -1) self.set_pay_from([]) msg = _('Amount to be sent.') + '\n\n' \ @@ -1113,22 +1113,22 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError): + _('Note that if you have frozen some of your addresses, the available funds will be lower than your total balance.') + '\n\n' \ + _('Keyboard shortcut: type "!" to send all your coins.') amount_label = HelpLabel(_('Amount'), msg) - grid.addWidget(amount_label, 4, 0) - grid.addWidget(self.amount_e, 4, 1) + grid.addWidget(amount_label, 5, 0) + grid.addWidget(self.amount_e, 5, 1) self.fiat_send_e = AmountEdit(self.fx.get_currency if self.fx else '') if not self.fx or not self.fx.is_enabled(): self.fiat_send_e.setVisible(False) - grid.addWidget(self.fiat_send_e, 4, 2) + grid.addWidget(self.fiat_send_e, 5, 2) self.amount_e.frozen.connect( lambda: self.fiat_send_e.setFrozen(self.amount_e.isReadOnly())) self.max_button = EnterButton(_("Max"), self.spend_max) self.max_button.setFixedWidth(140) - grid.addWidget(self.max_button, 4, 3) + grid.addWidget(self.max_button, 5, 3) hbox = QHBoxLayout() hbox.addStretch(1) - grid.addLayout(hbox, 4, 4) + grid.addLayout(hbox, 5, 4) msg = _('Bitcoin transactions are in general not free. A transaction fee is paid by the sender of the funds.') + '\n\n'\ + _('The amount of fee can be decided freely by the sender. However, transactions with low fees take more time to be processed.') + '\n\n'\ @@ -1209,7 +1209,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError): vbox_feelabel = QVBoxLayout() vbox_feelabel.addWidget(self.fee_e_label) vbox_feelabel.addStretch(1) - grid.addLayout(vbox_feelabel, 5, 0) + grid.addLayout(vbox_feelabel, 6, 0) self.fee_adv_controls = QWidget() hbox = QHBoxLayout(self.fee_adv_controls) @@ -1224,7 +1224,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError): vbox_feecontrol.addWidget(self.fee_adv_controls) vbox_feecontrol.addWidget(self.fee_slider) - grid.addLayout(vbox_feecontrol, 5, 1, 1, -1) + grid.addLayout(vbox_feecontrol, 6, 1, 1, -1) if not self.config.get('show_fee', False): self.fee_adv_controls.setVisible(False) @@ -1238,7 +1238,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError): buttons.addWidget(self.clear_button) buttons.addWidget(self.preview_button) buttons.addWidget(self.send_button) - grid.addLayout(buttons, 6, 1, 1, 3) + grid.addLayout(buttons, 7, 1, 1, 3) self.amount_e.shortcut.connect(self.spend_max) self.payto_e.textChanged.connect(self.update_fee) @@ -1496,7 +1496,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError): self.show_error(_('Payment request has expired')) return label = self.message_e.text() - flodata = self.message_tx.text() + flodata = self.message_tx_e.text() if self.payment_request: outputs = self.payment_request.get_outputs() @@ -1773,7 +1773,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError): self.not_enough_funds = False self.payment_request = None self.payto_e.is_pr = False - for e in [self.payto_e, self.message_e, self.amount_e, self.fiat_send_e, + for e in [self.payto_e, self.message_e, self.message_tx_e, self.amount_e, self.fiat_send_e, self.fee_e, self.feerate_e]: e.setText('') e.setFrozen(False) diff --git a/electrum/paymentrequest_pb2.py b/electrum/paymentrequest_pb2.py index f596128c..20cb32c2 100644 --- a/electrum/paymentrequest_pb2.py +++ b/electrum/paymentrequest_pb2.py @@ -18,6 +18,7 @@ _sym_db = _symbol_database.Default() DESCRIPTOR = _descriptor.FileDescriptor( name='paymentrequest.proto', package='payments', + syntax='proto2', serialized_pb=_b('\n\x14paymentrequest.proto\x12\x08payments\"+\n\x06Output\x12\x11\n\x06\x61mount\x18\x01 \x01(\x04:\x01\x30\x12\x0e\n\x06script\x18\x02 \x02(\x0c\"\xa3\x01\n\x0ePaymentDetails\x12\x15\n\x07network\x18\x01 \x01(\t:\x04main\x12!\n\x07outputs\x18\x02 \x03(\x0b\x32\x10.payments.Output\x12\x0c\n\x04time\x18\x03 \x02(\x04\x12\x0f\n\x07\x65xpires\x18\x04 \x01(\x04\x12\x0c\n\x04memo\x18\x05 \x01(\t\x12\x13\n\x0bpayment_url\x18\x06 \x01(\t\x12\x15\n\rmerchant_data\x18\x07 \x01(\x0c\"\x95\x01\n\x0ePaymentRequest\x12\"\n\x17payment_details_version\x18\x01 \x01(\r:\x01\x31\x12\x16\n\x08pki_type\x18\x02 \x01(\t:\x04none\x12\x10\n\x08pki_data\x18\x03 \x01(\x0c\x12\"\n\x1aserialized_payment_details\x18\x04 \x02(\x0c\x12\x11\n\tsignature\x18\x05 \x01(\x0c\"\'\n\x10X509Certificates\x12\x13\n\x0b\x63\x65rtificate\x18\x01 \x03(\x0c\"i\n\x07Payment\x12\x15\n\rmerchant_data\x18\x01 \x01(\x0c\x12\x14\n\x0ctransactions\x18\x02 \x03(\x0c\x12#\n\trefund_to\x18\x03 \x03(\x0b\x32\x10.payments.Output\x12\x0c\n\x04memo\x18\x04 \x01(\t\">\n\nPaymentACK\x12\"\n\x07payment\x18\x01 \x02(\x0b\x32\x11.payments.Payment\x12\x0c\n\x04memo\x18\x02 \x01(\tB(\n\x1eorg.bitcoin.protocols.paymentsB\x06Protos') ) _sym_db.RegisterFileDescriptor(DESCRIPTOR) @@ -54,6 +55,7 @@ _OUTPUT = _descriptor.Descriptor( ], options=None, is_extendable=False, + syntax='proto2', extension_ranges=[], oneofs=[ ], @@ -126,6 +128,7 @@ _PAYMENTDETAILS = _descriptor.Descriptor( ], options=None, is_extendable=False, + syntax='proto2', extension_ranges=[], oneofs=[ ], @@ -184,6 +187,7 @@ _PAYMENTREQUEST = _descriptor.Descriptor( ], options=None, is_extendable=False, + syntax='proto2', extension_ranges=[], oneofs=[ ], @@ -214,6 +218,7 @@ _X509CERTIFICATES = _descriptor.Descriptor( ], options=None, is_extendable=False, + syntax='proto2', extension_ranges=[], oneofs=[ ], @@ -265,6 +270,7 @@ _PAYMENT = _descriptor.Descriptor( ], options=None, is_extendable=False, + syntax='proto2', extension_ranges=[], oneofs=[ ], @@ -302,6 +308,7 @@ _PAYMENTACK = _descriptor.Descriptor( ], options=None, is_extendable=False, + syntax='proto2', extension_ranges=[], oneofs=[ ], diff --git a/run_electrum b/run_electrum index a254fabb..6558d960 100755 --- a/run_electrum +++ b/run_electrum @@ -362,7 +362,8 @@ if __name__ == '__main__': args = parser.parse_args() # config is an object passed to the various constructors (wallet, interface, gui) - if is_android: + #if is_android: + if True: config_options = { 'verbosity': '', 'cmd': 'gui',