You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

293 lines
9.6 KiB

from typing import TYPE_CHECKING
from kivy.app import App
from kivy.clock import Clock
from kivy.factory import Factory
from kivy.properties import ObjectProperty
from kivy.lang import Builder
from decimal import Decimal
from kivy.uix.popup import Popup
from electrum.gui.kivy.i18n import _
from ...util import address_colors
if TYPE_CHECKING:
from ...main_window import ElectrumWindow
Builder.load_string('''
<AddressLabel@Label>
text_size: self.width, None
halign: 'left'
valign: 'top'
<AddressItem@CardItem>
address: ''
memo: ''
amount: ''
status: ''
is_frozen: False
BoxLayout:
spacing: '8dp'
height: '32dp'
orientation: 'vertical'
Widget
AddressLabel:
text: root.address
shorten: True
Widget
AddressLabel:
text:
(("({}) ".format(_("Frozen")) if root.is_frozen else "")
+ (root.amount if root.status == 'Funded' else root.status) + ' ' + root.memo)
color: .699, .699, .699, 1
font_size: '13sp'
shorten: True
Widget
<AddressButton@Button>:
background_color: 1, .585, .878, 0
halign: 'center'
text_size: (self.width, None)
shorten: True
size_hint: 0.5, None
default_text: ''
text: self.default_text
padding: '5dp', '5dp'
height: '40dp'
text_color: self.foreground_color
disabled_color: 1, 1, 1, 1
foreground_color: 1, 1, 1, 1
canvas.before:
Color:
rgba: (0.9, .498, 0.745, 1) if self.state == 'down' else self.background_color
Rectangle:
size: self.size
pos: self.pos
<AddressesDialog@Popup>
id: popup
title: _('Addresses')
message: ''
pr_status: 'Pending'
show_change: 0
show_used: 0
on_message:
self.update()
BoxLayout:
id:box
padding: '12dp', '12dp', '12dp', '12dp'
spacing: '12dp'
orientation: 'vertical'
BoxLayout:
spacing: '6dp'
height: self.minimum_height
size_hint: 1, None
orientation: 'horizontal'
AddressFilter:
opacity: 1
size_hint: 1, None
height: self.minimum_height
spacing: '5dp'
AddressButton:
id: search
text: {0:_('Receiving'), 1:_('Change'), 2:_('All')}[root.show_change]
on_release:
root.show_change = (root.show_change + 1) % 3
Clock.schedule_once(lambda dt: root.update())
AddressFilter:
opacity: 1
size_hint: 1, None
height: self.minimum_height
spacing: '5dp'
AddressButton:
id: search
text: {0:_('All'), 1:_('Unused'), 2:_('Funded'), 3:_('Used'), 4:(_('Funded')+'|'+_('Unused'))}[root.show_used]
on_release:
root.show_used = (root.show_used + 1) % 5
Clock.schedule_once(lambda dt: root.update())
AddressFilter:
opacity: 1
size_hint: 1, None
height: self.minimum_height
spacing: '5dp'
canvas.before:
Color:
rgba: 0.9, 0.9, 0.9, 1
AddressButton:
id: change
text: root.message if root.message else _('Search')
on_release: Clock.schedule_once(lambda dt: app.description_dialog(popup))
RecycleView:
scroll_type: ['bars', 'content']
bar_width: '15dp'
viewclass: 'AddressItem'
id: search_container
RecycleBoxLayout:
orientation: 'vertical'
default_size: None, dp(56)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
<AddressPopup@Popup>:
address: ''
balance: ''
status: ''
script_type: ''
pk: ''
is_frozen: False
address_color: 1, 1, 1, 1
address_background_color: 0.3, 0.3, 0.3, 1
BoxLayout:
orientation: 'vertical'
ScrollView:
GridLayout:
cols: 1
height: self.minimum_height
size_hint_y: None
padding: '10dp'
spacing: '10dp'
TopLabel:
text: _('Address')
RefLabel:
color: root.address_color
background_color: root.address_background_color
data: root.address
name: _('Address')
GridLayout:
cols: 1
size_hint_y: None
height: self.minimum_height
spacing: '10dp'
BoxLabel:
text: _('Balance')
value: root.balance
BoxLabel:
text: _('Script type')
value: root.script_type
BoxLabel:
text: _('Status')
value: root.status
BoxLabel:
text: _('Frozen')
value: str(root.is_frozen)
TopLabel:
text: _('Private Key')
RefLabel:
data: root.pk
name: _('Private key')
on_touched: if not self.data: root.do_export(self)
Widget:
size_hint: 1, 0.1
BoxLayout:
size_hint: 1, None
height: '48dp'
Button:
size_hint: 0.5, None
height: '48dp'
text: _('Receive')
on_release: root.receive_at()
Button:
size_hint: 0.5, None
height: '48dp'
text: _('Freeze') if not root.is_frozen else _('Unfreeze')
on_release: root.freeze_address()
Button:
size_hint: 0.5, None
height: '48dp'
text: _('Close')
on_release: root.dismiss()
''')
class AddressPopup(Popup):
def __init__(self, parent, address, balance, status, **kwargs):
super(AddressPopup, self).__init__(**kwargs)
self.title = _('Address Details')
self.parent_dialog = parent
self.app = parent.app # type: ElectrumWindow
self.address = address
self.status = status
self.script_type = self.app.wallet.get_txin_type(self.address)
self.balance = self.app.format_amount_and_units(balance)
self.address_color, self.address_background_color = address_colors(self.app.wallet, address)
self.is_frozen = self.app.wallet.is_frozen_address(address)
def receive_at(self):
self.dismiss()
self.parent_dialog.dismiss()
self.app.switch_to('receive')
# retry until receive_screen is set
Clock.schedule_interval(lambda dt: bool(self.app.receive_screen.set_address(self.address) and False) if self.app.receive_screen else True, 0.1)
def do_export(self, pk_label):
self.app.export_private_keys(pk_label, self.address)
def freeze_address(self):
self.is_frozen = not self.is_frozen
self.app.wallet.set_frozen_state_of_addresses([self.address], freeze=self.is_frozen)
self.parent_dialog.update()
class AddressesDialog(Factory.Popup):
def __init__(self, app: 'ElectrumWindow'):
Factory.Popup.__init__(self)
self.app = app
self.update()
def get_card(self, addr, balance, is_used, label):
ci = {}
ci['screen'] = self
ci['address'] = addr
ci['memo'] = label
ci['amount'] = self.app.format_amount_and_units(balance)
ci['status'] = _('Used') if is_used else _('Funded') if balance > 0 else _('Unused')
ci['is_frozen'] = self.app.wallet.is_frozen_address(addr)
return ci
def update(self):
wallet = self.app.wallet
if self.show_change == 0:
_list = wallet.get_receiving_addresses()
elif self.show_change == 1:
_list = wallet.get_change_addresses()
else:
_list = wallet.get_addresses()
search = self.message
container = self.ids.search_container
n = 0
cards = []
for address in _list:
label = wallet.get_label(address)
balance = sum(wallet.get_addr_balance(address))
is_used_and_empty = wallet.is_used(address) and balance == 0
if self.show_used == 1 and (balance or is_used_and_empty):
continue
if self.show_used == 2 and balance == 0:
continue
if self.show_used == 3 and not is_used_and_empty:
continue
if self.show_used == 4 and is_used_and_empty:
continue
card = self.get_card(address, balance, is_used_and_empty, label)
if search and not self.ext_search(card, search):
continue
cards.append(card)
n += 1
container.data = cards
if not n:
self.app.show_error('No address matching your search')
def show_item(self, obj):
address = obj.address
c, u, x = self.app.wallet.get_addr_balance(address)
balance = c + u + x
d = AddressPopup(self, address, balance, obj.status)
d.open()
def ext_search(self, card, search):
return card['memo'].find(search) >= 0 or card['amount'].find(search) >= 0