update network settings dialog of the kivy GUI

This commit is contained in:
ThomasV 2017-07-10 13:51:13 +02:00
parent 92b392a56b
commit 73b023e967
10 changed files with 277 additions and 261 deletions

View File

@ -293,6 +293,34 @@
size: self.width - sp(4), self.height - sp(4)
<SettingsItem@ButtonBehavior+BoxLayout>
orientation: 'vertical'
title: ''
description: ''
size_hint: 1, None
height: '60dp'
canvas.before:
Color:
rgba: (0.192, .498, 0.745, 1) if self.state == 'down' else (0.3, 0.3, 0.3, 0)
Rectangle:
size: self.size
pos: self.pos
on_release:
Clock.schedule_once(self.action)
Widget
TopLabel:
id: title
text: self.parent.title
bold: True
halign: 'left'
TopLabel:
text: self.parent.description
color: 0.8, 0.8, 0.8, 1
halign: 'left'
Widget
<ScreenTabs@Screen>
TabbedCarousel:
@ -365,7 +393,7 @@ BoxLayout:
app_icon_width: '100dp'
with_previous: False
size_hint_x: None
on_release: app.popup_dialog('status')
on_release: app.popup_dialog('network')
ActionButton:
id: action_status
@ -386,6 +414,9 @@ BoxLayout:
ActionOvrButton:
name: 'wallets'
text: _('Wallets')
ActionOvrButton:
name: 'network'
text: _('Network')
ActionOvrButton:
name: 'settings'
text: _('Settings')

View File

@ -73,10 +73,55 @@ from electrum.util import base_units
class ElectrumWindow(App):
electrum_config = ObjectProperty(None)
language = StringProperty('en')
# properties might be updated by the network
num_blocks = NumericProperty(0)
num_nodes = NumericProperty(0)
server_host = StringProperty('')
server_port = StringProperty('')
auto_connect = BooleanProperty(False)
def on_auto_connect(self, instance, x):
host, port, protocol, proxy, auto_connect = self.network.get_parameters()
self.network.set_parameters(host, port, protocol, proxy, self.auto_connect)
def toggle_auto_connect(self, x):
self.auto_connect = not self.auto_connect
def choose_server_dialog(self, popup):
from uix.dialogs.choice_dialog import ChoiceDialog
protocol = 's'
def cb2(host):
from electrum.network import DEFAULT_PORTS
pp = servers.get(host, DEFAULT_PORTS)
port = pp.get(protocol, '')
popup.ids.host.text = host
popup.ids.port.text = port
servers = self.network.get_servers()
ChoiceDialog(_('Choose a server'), sorted(servers), popup.ids.host.text, cb2).open()
def choose_blockchain_dialog(self, dt):
from uix.dialogs.choice_dialog import ChoiceDialog
def cb(name):
for index, b in self.network.blockchains.items():
if name == self.network.get_blockchain_name(b):
self.network.follow_chain(index)
#self.block
names = [self.network.get_blockchain_name(b) for b in self.network.blockchains.values()]
if len(names) >1:
ChoiceDialog(_('Choose your chain'), names, '', cb).open()
use_rbf = BooleanProperty(False)
def on_use_rbf(self, instance, x):
self.electrum_config.set_key('use_rbf', self.use_rbf, True)
use_change = BooleanProperty(False)
def on_use_change(self, instance, x):
self.electrum_config.set_key('use_change', self.use_change, True)
use_unconfirmed = BooleanProperty(False)
def on_use_unconfirmed(self, instance, x):
self.electrum_config.set_key('confirmed_only', not self.use_unconfirmed, True)
def set_URI(self, uri):
self.switch_to('send')
@ -195,13 +240,26 @@ class ElectrumWindow(App):
title = _('Electrum App')
self.electrum_config = config = kwargs.get('config', None)
self.language = config.get('language', 'en')
self.network = network = kwargs.get('network', None)
self.plugins = kwargs.get('plugins', [])
self.network = network = kwargs.get('network', None)
if self.network:
self.num_blocks = self.network.get_local_height()
self.num_nodes = len(self.network.get_interfaces())
host, port, protocol, proxy_config, auto_connect = self.network.get_parameters()
self.server_host = host
self.server_port = port
self.auto_connect = auto_connect
self.proxy_config = proxy_config if proxy_config else {}
self.plugins = kwargs.get('plugins', [])
self.gui_object = kwargs.get('gui_object', None)
self.daemon = self.gui_object.daemon
self.fx = self.daemon.fx
self.use_rbf = config.get('use_rbf', False)
self.use_change = config.get('use_change', True)
self.use_unconfirmed = not config.get('confirmed_only', True)
# create triggers so as to minimize updation a max of 2 times a sec
self._trigger_update_wallet = Clock.create_trigger(self.update_wallet, .5)
self._trigger_update_status = Clock.create_trigger(self.update_status, .5)
@ -529,14 +587,31 @@ class ElectrumWindow(App):
if self.network:
interests = ['updated', 'status', 'new_transaction', 'verified']
self.network.register_callback(self.on_network, interests)
self.tabs = self.root.ids['tabs']
def blockchain_status(self):
if len(self.network.blockchains)>1:
msg = self.network.get_blockchain_name(self.network.blockchain())
else:
msg = _('Genesis block')
return msg
def blockchain_info(self):
if len(self.network.blockchains)>1:
checkpoint = self.network.get_checkpoint()
msg = _('Chain split detected at block %d')%checkpoint
else:
msg = _('No chain split detected')
return msg
def on_network(self, event, *args):
if self.network.interface:
self.server_host = self.network.interface.host
if event == 'updated':
self.num_blocks = self.network.get_local_height()
self.num_nodes = len(self.network.get_interfaces())
self._trigger_update_wallet()
self._trigger_update_status()
elif event == 'status':
self._trigger_update_status()
elif event == 'new_transaction':
@ -573,9 +648,11 @@ class ElectrumWindow(App):
text = self.format_amount(c+x+u)
status = str(text.strip() + ' ' + self.base_unit)
else:
status = _("Not connected")
status = _("Disconnected")
n = self.wallet.basename()
self.status = '[size=15dp]%s[/size]\n%s' %(n, status)
#fiat_balance = self.fx.format_amount_and_units(c+u+x) or ''
def get_max_amount(self):
inputs = self.wallet.get_spendable_coins(None, self.electrum_config)

View File

@ -79,7 +79,7 @@ Builder.load_string('''
id: button_fiat
size_hint: 1, None
height: '48dp'
text: (app.base_unit if kb.is_fiat else app.fiat_unit) if app.fiat_unit else ''
text: (app.base_unit if not kb.is_fiat else app.fiat_unit) if app.fiat_unit else ''
on_release:
if app.fiat_unit: popup.toggle_fiat(kb)
Button:

View File

@ -1,63 +0,0 @@
from kivy.app import App
from kivy.factory import Factory
from kivy.properties import ObjectProperty
from kivy.lang import Builder
from electrum.i18n import _
Builder.load_string('''
#:import _ electrum_gui.kivy.i18n._
<BlockchainDialog@Popup>
id: popup
title: _('Blockchain')
size_hint: 1, 1
cp_height: 0
cp_value: ''
BoxLayout:
orientation: 'vertical'
padding: '10dp'
spacing: '10dp'
TopLabel:
height: '48dp'
id: bc_height
text: _("Verified headers: %d blocks.")% app.num_blocks
TopLabel:
height: '48dp'
id: bc_status
text: _("Connected to %d nodes.")% app.num_nodes if app.num_nodes else _("Not connected?")
Widget:
size_hint: 1, 0.1
TopLabel:
text: _("Electrum connects to several nodes in order to download block headers and find out the longest blockchain.") + _("This blockchain is used to verify the transactions sent by your transaction server.")
font_size: '6pt'
Widget:
size_hint: 1, 0.1
Widget:
size_hint: 1, 0.1
BoxLayout:
orientation: 'horizontal'
size_hint: 1, 0.2
Button:
text: _('Cancel')
size_hint: 0.5, None
height: '48dp'
on_release: popup.dismiss()
Button:
text: _('OK')
size_hint: 0.5, None
height: '48dp'
on_release:
root.callback(root.cp_height, root.cp_value)
popup.dismiss()
''')
class BlockchainDialog(Factory.Popup):
def __init__(self, network, callback):
Factory.Popup.__init__(self)
self.network = network
self.callback = callback
self.is_split = len(self.network.blockchains) > 1
self.checkpoint_height = network.get_checkpoint()

View File

@ -16,35 +16,6 @@ Builder.load_string('''
#:import partial functools.partial
#:import _ electrum_gui.kivy.i18n._
<SettingsItem@ButtonBehavior+BoxLayout>
orientation: 'vertical'
title: ''
description: ''
size_hint: 1, None
height: '60dp'
canvas.before:
Color:
rgba: (0.192, .498, 0.745, 1) if self.state == 'down' else (0.3, 0.3, 0.3, 0)
Rectangle:
size: self.size
pos: self.pos
on_release:
Clock.schedule_once(self.action)
Widget
TopLabel:
id: title
text: self.parent.title
bold: True
halign: 'left'
TopLabel:
text: self.parent.description
color: 0.8, 0.8, 0.8, 1
halign: 'left'
Widget
<SettingsDialog@Popup>
id: settings
title: _('Electrum Settings')
@ -90,18 +61,6 @@ Builder.load_string('''
description: _("Display amounts in fiat currency.")
action: partial(root.fx_dialog, self)
CardSeparator
SettingsItem:
status: root.network_status()
title: _('Server') + ': ' + self.status
description: _("Select your history server.")
action: partial(root.network_dialog, self)
CardSeparator
SettingsItem:
status: root.proxy_status()
title: _('Proxy') + ': ' + self.status
description: _("Proxy configuration.")
action: partial(root.proxy_dialog, self)
CardSeparator
SettingsItem:
status: 'ON' if bool(app.plugins.get('labels')) else 'OFF'
title: _('Labels Sync') + ': ' + self.status
@ -109,22 +68,34 @@ Builder.load_string('''
action: partial(root.plugin_dialog, 'labels', self)
CardSeparator
SettingsItem:
status: root.rbf_status()
status: 'ON' if app.use_rbf else 'OFF'
title: _('Replace-by-fee') + ': ' + self.status
description: _("Create replaceable transactions.")
action: partial(root.rbf_dialog, self)
message:
_('If you check this box, your transactions will be marked as non-final,') \
+ ' ' + _('and you will have the possiblity, while they are unconfirmed, to replace them with transactions that pays higher fees.') \
+ ' ' + _('Note that some merchants do not accept non-final transactions until they are confirmed.')
action: partial(root.boolean_dialog, 'use_rbf', _('Replace by fee'), self.message)
CardSeparator
SettingsItem:
status: _('Yes') if app.use_unconfirmed else _('No')
title: _('Spend unconfirmed') + ': ' + self.status
description: _("Use unconfirmed coins in transactions.")
message: _('Spend unconfirmed coins')
action: partial(root.boolean_dialog, 'use_unconfirmed', _('Use unconfirmed'), self.message)
CardSeparator
SettingsItem:
status: _('Yes') if app.use_change else _('No')
title: _('Use change addresses') + ': ' + self.status
description: _("Send your change to separate addresses.")
message: _('Send excess coins to change addresses')
action: partial(root.boolean_dialog, 'use_change', _('Use change addresses'), self.message)
CardSeparator
SettingsItem:
status: root.coinselect_status()
title: _('Coin selection') + ': ' + self.status
description: "Coin selection method"
action: partial(root.coinselect_dialog, self)
CardSeparator
SettingsItem:
status: "%d blocks"% app.num_blocks
title: _('Blockchain') + ': ' + self.status
description: _("Blockchain status")
action: partial(root.blockchain_dialog, self)
''')
@ -141,13 +112,10 @@ class SettingsDialog(Factory.Popup):
# cached dialogs
self._fx_dialog = None
self._fee_dialog = None
self._rbf_dialog = None
self._network_dialog = None
self._proxy_dialog = None
self._language_dialog = None
self._unit_dialog = None
self._coinselect_dialog = None
self._blockchain_dialog = None
def update(self):
self.wallet = self.app.wallet
@ -191,15 +159,6 @@ class SettingsDialog(Factory.Popup):
self._coinselect_dialog = ChoiceDialog(_('Coin selection'), choosers, chooser_name, cb)
self._coinselect_dialog.open()
def blockchain_dialog(self, item, dt):
from blockchain_dialog import BlockchainDialog
if self._blockchain_dialog is None:
def callback(height, value):
if value:
self.app.network.blockchain.set_checkpoint(height, value)
self._blockchain_dialog = BlockchainDialog(self.app.network, callback)
self._blockchain_dialog.open()
def proxy_status(self):
server, port, protocol, proxy, auto_connect = self.app.network.get_parameters()
return proxy.get('host') +':' + proxy.get('port') if proxy else _('None')
@ -230,44 +189,11 @@ class SettingsDialog(Factory.Popup):
self._proxy_dialog = popup
self._proxy_dialog.open()
def network_dialog(self, item, dt):
host, port, protocol, proxy, auto_connect = self.app.network.get_parameters()
servers = self.app.network.get_servers()
if self._network_dialog is None:
def cb1(popup):
host = str(popup.ids.host.text)
port = str(popup.ids.port.text)
auto_connect = popup.ids.auto_connect.active
self.app.network.set_parameters(host, port, protocol, proxy, auto_connect)
item.status = self.network_status()
def cb2(host):
from electrum.network import DEFAULT_PORTS
pp = servers.get(host, DEFAULT_PORTS)
port = pp.get(protocol, '')
popup.ids.host.text = host
popup.ids.port.text = port
def cb3():
ChoiceDialog(_('Choose a server'), sorted(servers), popup.ids.host.text, cb2).open()
popup = Builder.load_file('gui/kivy/uix/ui_screens/network.kv')
popup.ids.chooser.on_release = cb3
popup.on_dismiss = lambda: cb1(popup)
self._network_dialog = popup
self._network_dialog.ids.auto_connect.active = auto_connect
self._network_dialog.ids.host.text = host
self._network_dialog.ids.port.text = port
self._network_dialog.open()
def network_status(self):
server, port, protocol, proxy, auto_connect = self.app.network.get_parameters()
return 'auto-connect' if auto_connect else server
def plugin_dialog(self, name, label, dt):
from checkbox_dialog import CheckBoxDialog
def callback(status):
self.plugins.enable(name) if status else self.plugins.disable(name)
label.status = 'ON' if status else 'OFF'
status = bool(self.plugins.get(name))
dd = self.plugins.descriptions.get(name)
descr = dd.get('description')
@ -289,21 +215,9 @@ class SettingsDialog(Factory.Popup):
self._fee_dialog = FeeDialog(self.app, self.config, cb)
self._fee_dialog.open()
def rbf_status(self):
return 'ON' if self.config.get('use_rbf') else 'OFF'
def rbf_dialog(self, label, dt):
if self._rbf_dialog is None:
from checkbox_dialog import CheckBoxDialog
def cb(x):
self.config.set_key('use_rbf', x, True)
label.status = self.rbf_status()
msg = [_('If you check this box, your transactions will be marked as non-final,'),
_('and you will have the possiblity, while they are unconfirmed, to replace them with transactions that pays higher fees.'),
_('Note that some merchants do not accept non-final transactions until they are confirmed.')]
fullname = _('Replace by fee')
self._rbf_dialog = CheckBoxDialog(fullname, ' '.join(msg), self.config.get('use_rbf', False), cb)
self._rbf_dialog.open()
def boolean_dialog(self, name, title, message, dt):
from checkbox_dialog import CheckBoxDialog
CheckBoxDialog(title, message, getattr(self.app, name), lambda x: setattr(self.app, name, x)).open()
def fx_status(self):
fx = self.app.fx

View File

@ -1,72 +1,53 @@
Popup:
id: nd
title: _('Server')
is_connected: app.network.is_connected()
title: _('Network')
BoxLayout:
orientation: 'vertical'
padding: '10dp'
spacing: '10dp'
TopLabel:
text: _("Electrum requests your transaction history from a single server. The returned history is then checked against blockchain headers sent by other nodes, using Simple Payment Verification (SPV).")
font_size: '6pt'
Widget:
size_hint: 1, 0.8
GridLayout:
cols: 3
Label:
height: '36dp'
size_hint_x: 1
size_hint_y: None
text: _('Host') + ':'
TextInput:
id: host
multiline: False
height: '36dp'
size_hint_x: 3
size_hint_y: None
text: ''
disabled: auto_connect.active
Button:
id: chooser
text:'v'
height: '36dp'
size_hint_x: 0.5
size_hint_y: None
disabled: auto_connect.active
Label:
height: '36dp'
size_hint_x: 1
size_hint_y: None
text: _('Port') + ':'
TextInput:
id: port
multiline: False
input_type: 'number'
height: '36dp'
size_hint_x: 3
size_hint_y: None
text: ''
disabled: auto_connect.active
Widget:
size_hint: 1, 0.1
TopLabel:
text: _("If auto-connect is checked, your history server will be selected automatically.")
font_size: '6pt'
BoxLayout:
Label:
text: _('Auto-connect')
CheckBox:
id: auto_connect
size_hint_y: None
Widget:
size_hint: 1, 0.1
BoxLayout:
Widget:
size_hint: 0.5, None
Button:
size_hint: 0.5, None
height: '48dp'
text: _('OK')
on_release:
nd.dismiss()
ScrollView:
GridLayout:
id: scrollviewlayout
cols:1
size_hint: 1, None
height: self.minimum_height
padding: '10dp'
SettingsItem:
value: _("%d connections.")% app.num_nodes if app.num_nodes else _("Not connected")
title: _("Status") + ': ' + self.value
description: _("Connections with Electrum servers")
action: lambda x: x
CardSeparator
SettingsItem:
title: _("Server") + ': ' + app.server_host
description: _("Server used to request your history.")
action: lambda x: app.popup_dialog('server')
CardSeparator
SettingsItem:
title: _("Auto-connect") + ': ' + ('ON' if app.auto_connect else 'OFF')
description: _("Find a server automatically")
action: app.toggle_auto_connect
CardSeparator
SettingsItem:
value: "%d blocks" % app.num_blocks
title: _("Blockchain") + ': ' + self.value
description: _("Verified block headers.")
action: lambda x: x
CardSeparator
SettingsItem:
title: _("Checkpoint") + ': ' + app.blockchain_status()
description: app.blockchain_info()
action: app.choose_blockchain_dialog
CardSeparator
SettingsItem:
proxy: app.proxy_config.get('mode')
host: app.proxy_config.get('host')
port: app.proxy_config.get('port')
title: _("Proxy") + ': ' + ((self.host +':' + self.port) if self.proxy else _('None'))
description: _('Proxy configuration')
action: lambda x: app.popup_dialog('proxy')

View File

@ -13,8 +13,8 @@ Popup:
id: mode
height: '48dp'
size_hint_y: None
text: ''
values: ['None', 'socks4', 'socks5', 'http']
text: app.proxy_config.get('mode', 'none')
values: ['none', 'socks4', 'socks5', 'http']
Label:
text: _('Host')
TextInput:
@ -22,8 +22,8 @@ Popup:
multiline: False
height: '48dp'
size_hint_y: None
text: ''
disabled: mode.text == 'None'
text: app.proxy_config.get('host', '')
disabled: mode.text == 'none'
Label:
text: _('Port')
TextInput:
@ -32,8 +32,8 @@ Popup:
input_type: 'number'
height: '48dp'
size_hint_y: None
text: ''
disabled: mode.text == 'None'
text: app.proxy_config.get('port', '')
disabled: mode.text == 'none'
Label:
text: _('Username')
TextInput:
@ -41,8 +41,8 @@ Popup:
multiline: False
height: '48dp'
size_hint_y: None
text: ''
disabled: mode.text == 'None'
text: app.proxy_config.get('user', '')
disabled: mode.text == 'none'
Label:
text: _('Password')
TextInput:
@ -51,8 +51,8 @@ Popup:
password: True
height: '48dp'
size_hint_y: None
text: ''
disabled: mode.text == 'None'
text: app.proxy_config.get('password', '')
disabled: mode.text == 'none'
Widget:
size_hint: 1, 0.1
BoxLayout:
@ -63,4 +63,14 @@ Popup:
height: '48dp'
text: _('OK')
on_release:
host, port, protocol, proxy, auto_connect = app.network.get_parameters()
proxy = {}
proxy['mode']=str(root.ids.mode.text).lower()
proxy['host']=str(root.ids.host.text)
proxy['port']=str(root.ids.port.text)
proxy['user']=str(root.ids.user.text)
proxy['password']=str(root.ids.password.text)
if proxy['mode']=='none': proxy = None
app.network.set_parameters(host, port, protocol, proxy, auto_connect)
app.proxy_config = proxy if proxy else {}
nd.dismiss()

View File

@ -0,0 +1,63 @@
Popup:
id: nd
title: _('Server')
BoxLayout:
orientation: 'vertical'
padding: '10dp'
spacing: '10dp'
TopLabel:
text: _("Electrum requests your transaction history from a single server. The returned history is checked against blockchain headers sent by other nodes, using Simple Payment Verification (SPV).")
font_size: '6pt'
Widget:
size_hint: 1, 0.8
GridLayout:
cols: 2
Label:
height: '36dp'
size_hint_x: 1
size_hint_y: None
text: _('Host') + ':'
TextInput:
id: host
multiline: False
height: '36dp'
size_hint_x: 3
size_hint_y: None
text: app.server_host
Label:
height: '36dp'
size_hint_x: 1
size_hint_y: None
text: _('Port') + ':'
TextInput:
id: port
multiline: False
input_type: 'number'
height: '36dp'
size_hint_x: 3
size_hint_y: None
text: app.server_port
Widget
Button:
id: chooser
text: _('Choose from peers')
height: '36dp'
size_hint_x: 0.5
size_hint_y: None
on_release:
app.choose_server_dialog(root)
Widget:
size_hint: 1, 0.1
BoxLayout:
Widget:
size_hint: 0.5, None
Button:
size_hint: 0.5, None
height: '48dp'
text: _('OK')
on_release:
host, port, protocol, proxy, auto_connect = app.network.get_parameters()
host = str(root.ids.host.text)
port = str(root.ids.port.text)
app.network.set_parameters(host, port, protocol, proxy, auto_connect)
nd.dismiss()

View File

@ -393,10 +393,6 @@ class NetworkChoiceLayout(object):
def follow_branch(self, index):
self.network.follow_chain(index)
server = self.network.interface.server
host, port, protocol, proxy, auto_connect = self.network.get_parameters()
host, port, protocol = server.split(':')
self.network.set_parameters(host, port, protocol, proxy, auto_connect)
self.update()
def follow_server(self, server):

View File

@ -1040,6 +1040,13 @@ class Network(util.DaemonThread):
else:
raise BaseException('blockchain not found', index)
if self.interface:
server = self.interface.server
host, port, protocol, proxy, auto_connect = self.get_parameters()
host, port, protocol = server.split(':')
self.set_parameters(host, port, protocol, proxy, auto_connect)
def get_local_height(self):
return self.blockchain().height()