1from typing import TYPE_CHECKING 2 3from kivy.factory import Factory 4from kivy.lang import Builder 5from kivy.core.clipboard import Clipboard 6from kivy.app import App 7from kivy.clock import Clock 8 9from electrum.gui.kivy.i18n import _ 10from electrum.invoices import pr_tooltips, pr_color 11from electrum.invoices import PR_UNKNOWN, PR_UNPAID, PR_FAILED, PR_TYPE_LN 12 13if TYPE_CHECKING: 14 from electrum.gui.kivy.main_window import ElectrumWindow 15 16 17Builder.load_string(''' 18#:import KIVY_GUI_PATH electrum.gui.kivy.KIVY_GUI_PATH 19 20<InvoiceDialog@Popup> 21 id: popup 22 amount_str: '' 23 title: '' 24 data: '' 25 description:'' 26 status_color: 1,1,1,1 27 status_str:'' 28 warning: '' 29 can_pay: True 30 shaded: False 31 show_text: False 32 AnchorLayout: 33 anchor_x: 'center' 34 BoxLayout: 35 orientation: 'vertical' 36 size_hint: 1, 1 37 padding: '10dp' 38 spacing: '10dp' 39 TopLabel: 40 text: _('Invoice data')+ ':' 41 RefLabel: 42 data: root.data 43 text: root.data[:40] + "..." 44 name: _('Data') 45 show_text_with_qr: False 46 TopLabel: 47 text: _('Description') + ':' 48 RefLabel: 49 data: root.description or _('No description') 50 TopLabel: 51 text: _('Amount') + ': ' + root.amount_str 52 TopLabel: 53 text: _('Status') + ': ' + root.status_str 54 color: root.status_color 55 on_touch_down: 56 touch = args[1] 57 touched = bool(self.collide_point(*touch.pos)) 58 if touched: root.show_log() 59 TopLabel: 60 text: root.warning 61 color: (0.9, 0.6, 0.3, 1) 62 Widget: 63 size_hint: 1, 0.2 64 BoxLayout: 65 size_hint: 1, None 66 height: '48dp' 67 Button: 68 size_hint: 1, None 69 height: '48dp' 70 text: _('Delete') 71 on_release: root.delete_dialog() 72 IconButton: 73 icon: f'atlas://{KIVY_GUI_PATH}/theming/atlas/light/copy' 74 size_hint: 0.5, None 75 height: '48dp' 76 on_release: root.copy_to_clipboard() 77 IconButton: 78 icon: f'atlas://{KIVY_GUI_PATH}/theming/atlas/light/share' 79 size_hint: 0.5, None 80 height: '48dp' 81 on_release: root.do_share() 82 Button: 83 size_hint: 1, None 84 height: '48dp' 85 text: _('Pay') 86 on_release: root.do_pay() 87 disabled: not root.can_pay 88''') 89 90class InvoiceDialog(Factory.Popup): 91 92 def __init__(self, title, data, key): 93 self.status = PR_UNKNOWN 94 Factory.Popup.__init__(self) 95 self.app = App.get_running_app() # type: ElectrumWindow 96 self.title = title 97 self.data = data 98 self.key = key 99 invoice = self.app.wallet.get_invoice(key) 100 self.amount_sat = invoice.get_amount_sat() 101 self.amount_str = self.app.format_amount_and_units(self.amount_sat) 102 self.description = invoice.message 103 self.is_lightning = invoice.is_lightning() 104 self.update_status() 105 self.log = self.app.wallet.lnworker.logs[self.key] if self.is_lightning and self.app.wallet.lnworker else [] 106 107 def update_status(self): 108 invoice = self.app.wallet.get_invoice(self.key) 109 self.status = self.app.wallet.get_invoice_status(invoice) 110 self.status_str = invoice.get_status_str(self.status) 111 self.status_color = pr_color[self.status] 112 self.can_pay = self.status in [PR_UNPAID, PR_FAILED] 113 if self.can_pay and self.is_lightning and self.app.wallet.lnworker: 114 if self.amount_sat and self.amount_sat > self.app.wallet.lnworker.num_sats_can_send(): 115 self.warning = _('Warning') + ': ' + _('This amount exceeds the maximum you can currently send with your channels') 116 117 def on_dismiss(self): 118 self.app.request_popup = None 119 120 def copy_to_clipboard(self): 121 Clipboard.copy(self.data) 122 msg = _('Text copied to clipboard.') 123 Clock.schedule_once(lambda dt: self.app.show_info(msg)) 124 125 def do_share(self): 126 self.app.do_share(self.data, _("Share Invoice")) 127 self.dismiss() 128 129 def do_pay(self): 130 invoice = self.app.wallet.get_invoice(self.key) 131 self.app.send_screen.do_pay_invoice(invoice) 132 self.dismiss() 133 134 def delete_dialog(self): 135 from .question import Question 136 def cb(result): 137 if result: 138 self.dismiss() 139 self.app.wallet.delete_invoice(self.key) 140 self.app.send_screen.update() 141 d = Question(_('Delete invoice?'), cb) 142 d.open() 143 144 def show_log(self): 145 if self.log: 146 log_str = _('Payment log:') + '\n\n' 147 for payment_attempt_log in self.log: 148 route_str, chan_str, message = payment_attempt_log.formatted_tuple() 149 log_str += chan_str + ' --- ' + message + '\n' 150 self.app.show_info(log_str) 151