URI: 
       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()