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