tsettings.py - electrum - Electrum Bitcoin wallet
HTML git clone https://git.parazyd.org/electrum
DIR Log
DIR Files
DIR Refs
DIR Submodules
---
tsettings.py (12163B)
---
1 from kivy.app import App
2 from kivy.factory import Factory
3 from kivy.properties import ObjectProperty
4 from kivy.lang import Builder
5
6 from electrum.util import base_units_list
7 from electrum.i18n import languages
8 from electrum.gui.kivy.i18n import _
9 from electrum.plugin import run_hook
10 from electrum import coinchooser
11
12 from electrum.gui.kivy import KIVY_GUI_PATH
13
14 from .choice_dialog import ChoiceDialog
15
16 Builder.load_string('''
17 #:import partial functools.partial
18 #:import _ electrum.gui.kivy.i18n._
19
20 <SettingsDialog@Popup>
21 id: settings
22 title: _('Electrum Settings')
23 has_pin_code: False
24 use_encryption: False
25 BoxLayout:
26 orientation: 'vertical'
27 ScrollView:
28 GridLayout:
29 id: scrollviewlayout
30 cols:1
31 size_hint: 1, None
32 height: self.minimum_height
33 padding: '10dp'
34 SettingsItem:
35 lang: settings.get_language_name()
36 title: 'Language' + ': ' + str(self.lang)
37 description: _('Language')
38 action: partial(root.language_dialog, self)
39 CardSeparator
40 SettingsItem:
41 status: 'ON' if root.has_pin_code else 'OFF'
42 title: _('PIN code') + ': ' + self.status
43 description: _("Change your PIN code.") if root.has_pin_code else _("Add PIN code")
44 action: partial(root.change_pin_code, self)
45 CardSeparator
46 SettingsItem:
47 bu: app.base_unit
48 title: _('Denomination') + ': ' + self.bu
49 description: _("Base unit for Bitcoin amounts.")
50 action: partial(root.unit_dialog, self)
51 CardSeparator
52 SettingsItem:
53 title: _('Onchain fees') + ': ' + app.fee_status
54 description: _('Choose how transaction fees are estimated')
55 action: lambda dt: app.fee_dialog()
56 CardSeparator
57 SettingsItem:
58 status: root.fx_status()
59 title: _('Fiat Currency') + ': ' + self.status
60 description: _("Display amounts in fiat currency.")
61 action: partial(root.fx_dialog, self)
62 CardSeparator
63 SettingsItem:
64 status: 'ON' if bool(app.plugins.get('labels')) else 'OFF'
65 title: _('Labels Sync') + ': ' + self.status
66 description: _("Save and synchronize your labels.")
67 action: partial(root.plugin_dialog, 'labels', self)
68 CardSeparator
69 SettingsItem:
70 status: 'ON' if app.use_rbf else 'OFF'
71 title: _('Replace-by-fee') + ': ' + self.status
72 description: _("Create replaceable transactions.")
73 message:
74 _('If you check this box, your transactions will be marked as non-final,') \
75 + ' ' + _('and you will have the possibility, while they are unconfirmed, to replace them with transactions that pays higher fees.') \
76 + ' ' + _('Note that some merchants do not accept non-final transactions until they are confirmed.')
77 action: partial(root.boolean_dialog, 'use_rbf', _('Replace by fee'), self.message)
78 CardSeparator
79 SettingsItem:
80 status: _('Yes') if app.use_unconfirmed else _('No')
81 title: _('Spend unconfirmed') + ': ' + self.status
82 description: _("Use unconfirmed coins in transactions.")
83 message: _('Spend unconfirmed coins')
84 action: partial(root.boolean_dialog, 'use_unconfirmed', _('Use unconfirmed'), self.message)
85 CardSeparator
86 SettingsItem:
87 status: _('Yes') if app.use_change else _('No')
88 title: _('Use change addresses') + ': ' + self.status
89 description: _("Send your change to separate addresses.")
90 message: _('Send excess coins to change addresses')
91 action: partial(root.boolean_dialog, 'use_change', _('Use change addresses'), self.message)
92 CardSeparator
93 SettingsItem:
94 title: _('Password')
95 description: _('Change your password') if app._use_single_password else _("Change your password for this wallet.")
96 action: root.change_password
97 CardSeparator
98 SettingsItem:
99 status: _('Trampoline') if not app.use_gossip else _('Gossip')
100 title: _('Lightning Routing') + ': ' + self.status
101 description: _("Use trampoline routing or gossip.")
102 action: partial(root.routing_dialog, self)
103 CardSeparator
104 SettingsItem:
105 status: _('Yes') if app.android_backups else _('No')
106 title: _('Backups') + ': ' + self.status
107 description: _("Backup wallet to external storage.")
108 message: _("If this option is checked, a backup of your wallet will be written to external storage everytime you create a new channel. Make sure your wallet is protected with a strong password before you enable this option.")
109 action: partial(root.boolean_dialog, 'android_backups', _('Backups'), self.message)
110
111 # disabled: there is currently only one coin selection policy
112 #CardSeparator
113 #SettingsItem:
114 # status: root.coinselect_status()
115 # title: _('Coin selection') + ': ' + self.status
116 # description: "Coin selection method"
117 # action: partial(root.coinselect_dialog, self)
118 ''')
119
120
121
122 class SettingsDialog(Factory.Popup):
123
124 def __init__(self, app):
125 self.app = app
126 self.plugins = self.app.plugins
127 self.config = self.app.electrum_config
128 Factory.Popup.__init__(self)
129 layout = self.ids.scrollviewlayout
130 layout.bind(minimum_height=layout.setter('height'))
131 # cached dialogs
132 self._fx_dialog = None
133 self._proxy_dialog = None
134 self._language_dialog = None
135 self._unit_dialog = None
136 self._coinselect_dialog = None
137
138 def update(self):
139 self.wallet = self.app.wallet
140 self.use_encryption = self.wallet.has_password() if self.wallet else False
141 self.has_pin_code = self.app.has_pin_code()
142
143 def get_language_name(self):
144 return languages.get(self.config.get('language', 'en_UK'), '')
145
146 def change_password(self, dt):
147 self.app.change_password(self.update)
148
149 def change_pin_code(self, label, dt):
150 self.app.change_pin_code(self.update)
151
152 def language_dialog(self, item, dt):
153 if self._language_dialog is None:
154 l = self.config.get('language', 'en_UK')
155 def cb(key):
156 self.config.set_key("language", key, True)
157 item.lang = self.get_language_name()
158 self.app.language = key
159 self._language_dialog = ChoiceDialog(_('Language'), languages, l, cb)
160 self._language_dialog.open()
161
162 def unit_dialog(self, item, dt):
163 if self._unit_dialog is None:
164 def cb(text):
165 self.app._set_bu(text)
166 item.bu = self.app.base_unit
167 self._unit_dialog = ChoiceDialog(_('Denomination'), base_units_list,
168 self.app.base_unit, cb, keep_choice_order=True)
169 self._unit_dialog.open()
170
171 def routing_dialog(self, item, dt):
172 description = \
173 _('Lightning payments require finding a path through the Lightning Network.')\
174 + ' ' + ('You may use trampoline routing, or local routing (gossip).')\
175 + ' ' + ('Downloading the network gossip uses quite some bandwidth and storage, and is not recommended on mobile devices.')\
176 + ' ' + ('If you use trampoline, you can only open channels with trampoline nodes.')
177 def cb(text):
178 self.app.use_gossip = (text == 'Gossip')
179 dialog = ChoiceDialog(
180 _('Lightning Routing'),
181 ['Trampoline', 'Gossip'],
182 'Gossip' if self.app.use_gossip else 'Trampoline',
183 cb, description=description,
184 keep_choice_order=True)
185 dialog.open()
186
187 def coinselect_status(self):
188 return coinchooser.get_name(self.app.electrum_config)
189
190 def coinselect_dialog(self, item, dt):
191 if self._coinselect_dialog is None:
192 choosers = sorted(coinchooser.COIN_CHOOSERS.keys())
193 chooser_name = coinchooser.get_name(self.config)
194 def cb(text):
195 self.config.set_key('coin_chooser', text)
196 item.status = text
197 self._coinselect_dialog = ChoiceDialog(_('Coin selection'), choosers, chooser_name, cb)
198 self._coinselect_dialog.open()
199
200 def proxy_status(self):
201 net_params = self.app.network.get_parameters()
202 proxy = net_params.proxy
203 return proxy.get('host') +':' + proxy.get('port') if proxy else _('None')
204
205 def proxy_dialog(self, item, dt):
206 network = self.app.network
207 if self._proxy_dialog is None:
208 net_params = network.get_parameters()
209 proxy = net_params.proxy
210 def callback(popup):
211 nonlocal net_params
212 if popup.ids.mode.text != 'None':
213 proxy = {
214 'mode':popup.ids.mode.text,
215 'host':popup.ids.host.text,
216 'port':popup.ids.port.text,
217 'user':popup.ids.user.text,
218 'password':popup.ids.password.text
219 }
220 else:
221 proxy = None
222 net_params = net_params._replace(proxy=proxy)
223 network.run_from_another_thread(network.set_parameters(net_params))
224 item.status = self.proxy_status()
225 popup = Builder.load_file(KIVY_GUI_PATH + '/uix/ui_screens/proxy.kv')
226 popup.ids.mode.text = proxy.get('mode') if proxy else 'None'
227 popup.ids.host.text = proxy.get('host') if proxy else ''
228 popup.ids.port.text = proxy.get('port') if proxy else ''
229 popup.ids.user.text = proxy.get('user') if proxy else ''
230 popup.ids.password.text = proxy.get('password') if proxy else ''
231 popup.on_dismiss = lambda: callback(popup)
232 self._proxy_dialog = popup
233 self._proxy_dialog.open()
234
235 def plugin_dialog(self, name, label, dt):
236 from .checkbox_dialog import CheckBoxDialog
237 def callback(status):
238 self.plugins.enable(name) if status else self.plugins.disable(name)
239 label.status = 'ON' if status else 'OFF'
240 status = bool(self.plugins.get(name))
241 dd = self.plugins.descriptions.get(name)
242 descr = dd.get('description')
243 fullname = dd.get('fullname')
244 d = CheckBoxDialog(fullname, descr, status, callback)
245 d.open()
246
247 def boolean_dialog(self, name, title, message, dt):
248 from .checkbox_dialog import CheckBoxDialog
249 CheckBoxDialog(title, message, getattr(self.app, name), lambda x: setattr(self.app, name, x)).open()
250
251 def fx_status(self):
252 fx = self.app.fx
253 if fx.is_enabled():
254 source = fx.exchange.name()
255 ccy = fx.get_currency()
256 return '%s [%s]' %(ccy, source)
257 else:
258 return _('None')
259
260 def fx_dialog(self, label, dt):
261 if self._fx_dialog is None:
262 from .fx_dialog import FxDialog
263 def cb():
264 label.status = self.fx_status()
265 self._fx_dialog = FxDialog(self.app, self.plugins, self.config, cb)
266 self._fx_dialog.open()