Example #1
0
    def settings_dialog(self, window):
        d = WindowModalDialog(window, _("Email settings"))
        d.setMinimumSize(500, 200)

        vbox = QVBoxLayout(d)
        vbox.addWidget(QLabel(_('Server hosting your email account')))
        grid = QGridLayout()
        vbox.addLayout(grid)
        grid.addWidget(QLabel('Server (IMAP)'), 0, 0)
        server_e = QLineEdit()
        server_e.setText(self.imap_server)
        grid.addWidget(server_e, 0, 1)

        grid.addWidget(QLabel('Username'), 1, 0)
        username_e = QLineEdit()
        username_e.setText(self.username)
        grid.addWidget(username_e, 1, 1)

        grid.addWidget(QLabel('Password'), 2, 0)
        password_e = QLineEdit()
        password_e.setText(self.password)
        grid.addWidget(password_e, 2, 1)

        vbox.addStretch()
        vbox.addLayout(Buttons(CloseButton(d), OkButton(d)))

        if not d.exec_():
            return

        server = str(server_e.text())
        self.config.set_key('email_server', server)
        self.imap_server = server

        username = str(username_e.text())
        self.config.set_key('email_username', username)
        self.username = username

        password = str(password_e.text())
        self.config.set_key('email_password', password)
        self.password = password

        check_connection = CheckConnectionThread(server, username, password)
        check_connection.connection_error_signal.connect(
            lambda e: window.show_message(
                _("Unable to connect to mail server:\n {}").format(e) + "\n" +
                _("Please check your connection and credentials.")))
        check_connection.start()
Example #2
0
    def calibration_dialog(self, window):
        d = WindowModalDialog(window,
                              _("Revealer - Printer calibration settings"))

        d.setMinimumSize(100, 200)

        vbox = QVBoxLayout(d)
        vbox.addWidget(
            QLabel(''.join([
                "<br/>",
                _("If you have an old printer, or want optimal precision"),
                "<br/>",
                _("print the calibration pdf and follow the instructions "),
                "<br/>",
                "<br/>",
            ])))
        self.calibration_h = self.config.get('calibration_h')
        self.calibration_v = self.config.get('calibration_v')
        cprint = QPushButton(_("Open calibration pdf"))
        cprint.clicked.connect(self.calibration)
        vbox.addWidget(cprint)

        vbox.addWidget(QLabel(_('Calibration values:')))
        grid = QGridLayout()
        vbox.addLayout(grid)
        grid.addWidget(QLabel(_('Right side')), 0, 0)
        horizontal = QLineEdit()
        horizontal.setText(str(self.calibration_h))
        grid.addWidget(horizontal, 0, 1)

        grid.addWidget(QLabel(_('Bottom')), 1, 0)
        vertical = QLineEdit()
        vertical.setText(str(self.calibration_v))
        grid.addWidget(vertical, 1, 1)

        vbox.addStretch()
        vbox.addSpacing(13)
        vbox.addLayout(Buttons(CloseButton(d), OkButton(d)))

        if not d.exec_():
            return

        self.calibration_h = int(Decimal(horizontal.text()))
        self.config.set_key('calibration_h', self.calibration_h)
        self.calibration_v = int(Decimal(vertical.text()))
        self.config.set_key('calibration_v', self.calibration_v)
Example #3
0
    def wallet_info_buttons(self, main_window, dialog):
        # user is about to see the "Wallet Information" dialog
        # - add a button if multisig wallet, and a Coldcard is a cosigner.
        wallet = main_window.wallet

        if type(wallet) is not Multisig_Wallet:
            return

        if not any(
                type(ks) == self.keystore_class
                for ks in wallet.get_keystores()):
            # doesn't involve a Coldcard wallet, hide feature
            return

        btn = QPushButton(_("Export for Coldcard"))
        btn.clicked.connect(
            lambda unused: self.export_multisig_setup(main_window, wallet))

        return Buttons(btn, CloseButton(dialog))
Example #4
0
    def __init__(self, window, plugin, keystore, device_id):
        title = _("{} Settings").format(plugin.device)
        super(SettingsDialog, self).__init__(window, title)
        self.setMaximumWidth(540)

        devmgr = plugin.device_manager()
        config = devmgr.config
        handler = keystore.handler
        thread = keystore.thread

        def invoke_client(method, *args, **kw_args):
            unpair_after = kw_args.pop('unpair_after', False)

            def task():
                client = devmgr.client_by_id(device_id)
                if not client:
                    raise RuntimeError("Device not connected")
                if method:
                    getattr(client, method)(*args, **kw_args)
                if unpair_after:
                    devmgr.unpair_id(device_id)
                return client.features

            thread.add(task, on_success=update)

        def update(features):
            self.features = features
            set_label_enabled()
            bl_hash = bh2u(features.bootloader_hash)
            bl_hash = "\n".join([bl_hash[:32], bl_hash[32:]])
            noyes = [_("No"), _("Yes")]
            endis = [_("Enable Passphrases"), _("Disable Passphrases")]
            disen = [_("Disabled"), _("Enabled")]
            setchange = [_("Set a PIN"), _("Change PIN")]

            version = "%d.%d.%d" % (features.major_version,
                                    features.minor_version,
                                    features.patch_version)
            coins = ", ".join(coin.coin_name for coin in features.coins)

            device_label.setText(features.label)
            pin_set_label.setText(noyes[features.pin_protection])
            passphrases_label.setText(disen[features.passphrase_protection])
            bl_hash_label.setText(bl_hash)
            label_edit.setText(features.label)
            device_id_label.setText(features.device_id)
            initialized_label.setText(noyes[features.initialized])
            version_label.setText(version)
            coins_label.setText(coins)
            clear_pin_button.setVisible(features.pin_protection)
            clear_pin_warning.setVisible(features.pin_protection)
            pin_button.setText(setchange[features.pin_protection])
            pin_msg.setVisible(not features.pin_protection)
            passphrase_button.setText(endis[features.passphrase_protection])
            language_label.setText(features.language)

        def set_label_enabled():
            label_apply.setEnabled(label_edit.text() != self.features.label)

        def rename():
            invoke_client('change_label', label_edit.text())

        def toggle_passphrase():
            title = _("Confirm Toggle Passphrase Protection")
            currently_enabled = self.features.passphrase_protection
            if currently_enabled:
                msg = _("After disabling passphrases, you can only pair this "
                        "Electrum wallet if it had an empty passphrase.  "
                        "If its passphrase was not empty, you will need to "
                        "create a new wallet with the install wizard.  You "
                        "can use this wallet again at any time by re-enabling "
                        "passphrases and entering its passphrase.")
            else:
                msg = _("Your current Electrum wallet can only be used with "
                        "an empty passphrase.  You must create a separate "
                        "wallet with the install wizard for other passphrases "
                        "as each one generates a new set of addresses.")
            msg += "\n\n" + _("Are you sure you want to proceed?")
            if not self.question(msg, title=title):
                return
            invoke_client('toggle_passphrase', unpair_after=currently_enabled)

        def set_pin():
            invoke_client('set_pin', remove=False)

        def clear_pin():
            invoke_client('set_pin', remove=True)

        def wipe_device():
            wallet = window.wallet
            if wallet and sum(wallet.get_balance()):
                title = _("Confirm Device Wipe")
                msg = _("Are you SURE you want to wipe the device?\n"
                        "Your wallet still has bitgesells in it!")
                if not self.question(
                        msg, title=title, icon=QMessageBox.Critical):
                    return
            invoke_client('wipe_device', unpair_after=True)

        def slider_moved():
            mins = timeout_slider.sliderPosition()
            timeout_minutes.setText(_("{:2d} minutes").format(mins))

        def slider_released():
            config.set_session_timeout(timeout_slider.sliderPosition() * 60)

        # Information tab
        info_tab = QWidget()
        info_layout = QVBoxLayout(info_tab)
        info_glayout = QGridLayout()
        info_glayout.setColumnStretch(2, 1)
        device_label = QLabel()
        pin_set_label = QLabel()
        passphrases_label = QLabel()
        version_label = QLabel()
        device_id_label = QLabel()
        bl_hash_label = QLabel()
        bl_hash_label.setWordWrap(True)
        coins_label = QLabel()
        coins_label.setWordWrap(True)
        language_label = QLabel()
        initialized_label = QLabel()
        rows = [
            (_("Device Label"), device_label),
            (_("PIN set"), pin_set_label),
            (_("Passphrases"), passphrases_label),
            (_("Firmware Version"), version_label),
            (_("Device ID"), device_id_label),
            (_("Bootloader Hash"), bl_hash_label),
            (_("Supported Coins"), coins_label),
            (_("Language"), language_label),
            (_("Initialized"), initialized_label),
        ]
        for row_num, (label, widget) in enumerate(rows):
            info_glayout.addWidget(QLabel(label), row_num, 0)
            info_glayout.addWidget(widget, row_num, 1)
        info_layout.addLayout(info_glayout)

        # Settings tab
        settings_tab = QWidget()
        settings_layout = QVBoxLayout(settings_tab)
        settings_glayout = QGridLayout()

        # Settings tab - Label
        label_msg = QLabel(
            _("Name this {}.  If you have multiple devices "
              "their labels help distinguish them.").format(plugin.device))
        label_msg.setWordWrap(True)
        label_label = QLabel(_("Device Label"))
        label_edit = QLineEdit()
        label_edit.setMinimumWidth(150)
        label_edit.setMaxLength(plugin.MAX_LABEL_LEN)
        label_apply = QPushButton(_("Apply"))
        label_apply.clicked.connect(rename)
        label_edit.textChanged.connect(set_label_enabled)
        settings_glayout.addWidget(label_label, 0, 0)
        settings_glayout.addWidget(label_edit, 0, 1, 1, 2)
        settings_glayout.addWidget(label_apply, 0, 3)
        settings_glayout.addWidget(label_msg, 1, 1, 1, -1)

        # Settings tab - PIN
        pin_label = QLabel(_("PIN Protection"))
        pin_button = QPushButton()
        pin_button.clicked.connect(set_pin)
        settings_glayout.addWidget(pin_label, 2, 0)
        settings_glayout.addWidget(pin_button, 2, 1)
        pin_msg = QLabel(
            _("PIN protection is strongly recommended.  "
              "A PIN is your only protection against someone "
              "stealing your bitgesells if they obtain physical "
              "access to your {}.").format(plugin.device))
        pin_msg.setWordWrap(True)
        pin_msg.setStyleSheet("color: red")
        settings_glayout.addWidget(pin_msg, 3, 1, 1, -1)

        # Settings tab - Session Timeout
        timeout_label = QLabel(_("Session Timeout"))
        timeout_minutes = QLabel()
        timeout_slider = QSlider(Qt.Horizontal)
        timeout_slider.setRange(1, 60)
        timeout_slider.setSingleStep(1)
        timeout_slider.setTickInterval(5)
        timeout_slider.setTickPosition(QSlider.TicksBelow)
        timeout_slider.setTracking(True)
        timeout_msg = QLabel(
            _("Clear the session after the specified period "
              "of inactivity.  Once a session has timed out, "
              "your PIN and passphrase (if enabled) must be "
              "re-entered to use the device."))
        timeout_msg.setWordWrap(True)
        timeout_slider.setSliderPosition(config.get_session_timeout() // 60)
        slider_moved()
        timeout_slider.valueChanged.connect(slider_moved)
        timeout_slider.sliderReleased.connect(slider_released)
        settings_glayout.addWidget(timeout_label, 6, 0)
        settings_glayout.addWidget(timeout_slider, 6, 1, 1, 3)
        settings_glayout.addWidget(timeout_minutes, 6, 4)
        settings_glayout.addWidget(timeout_msg, 7, 1, 1, -1)
        settings_layout.addLayout(settings_glayout)
        settings_layout.addStretch(1)

        # Advanced tab
        advanced_tab = QWidget()
        advanced_layout = QVBoxLayout(advanced_tab)
        advanced_glayout = QGridLayout()

        # Advanced tab - clear PIN
        clear_pin_button = QPushButton(_("Disable PIN"))
        clear_pin_button.clicked.connect(clear_pin)
        clear_pin_warning = QLabel(
            _("If you disable your PIN, anyone with physical access to your "
              "{} device can spend your bitgesells.").format(plugin.device))
        clear_pin_warning.setWordWrap(True)
        clear_pin_warning.setStyleSheet("color: red")
        advanced_glayout.addWidget(clear_pin_button, 0, 2)
        advanced_glayout.addWidget(clear_pin_warning, 1, 0, 1, 5)

        # Advanced tab - toggle passphrase protection
        passphrase_button = QPushButton()
        passphrase_button.clicked.connect(toggle_passphrase)
        passphrase_msg = WWLabel(PASSPHRASE_HELP)
        passphrase_warning = WWLabel(PASSPHRASE_NOT_PIN)
        passphrase_warning.setStyleSheet("color: red")
        advanced_glayout.addWidget(passphrase_button, 3, 2)
        advanced_glayout.addWidget(passphrase_msg, 4, 0, 1, 5)
        advanced_glayout.addWidget(passphrase_warning, 5, 0, 1, 5)

        # Advanced tab - wipe device
        wipe_device_button = QPushButton(_("Wipe Device"))
        wipe_device_button.clicked.connect(wipe_device)
        wipe_device_msg = QLabel(
            _("Wipe the device, removing all data from it.  The firmware "
              "is left unchanged."))
        wipe_device_msg.setWordWrap(True)
        wipe_device_warning = QLabel(
            _("Only wipe a device if you have the recovery seed written down "
              "and the device wallet(s) are empty, otherwise the bitgesells "
              "will be lost forever."))
        wipe_device_warning.setWordWrap(True)
        wipe_device_warning.setStyleSheet("color: red")
        advanced_glayout.addWidget(wipe_device_button, 6, 2)
        advanced_glayout.addWidget(wipe_device_msg, 7, 0, 1, 5)
        advanced_glayout.addWidget(wipe_device_warning, 8, 0, 1, 5)
        advanced_layout.addLayout(advanced_glayout)
        advanced_layout.addStretch(1)

        tabs = QTabWidget(self)
        tabs.addTab(info_tab, _("Information"))
        tabs.addTab(settings_tab, _("Settings"))
        tabs.addTab(advanced_tab, _("Advanced"))
        dialog_vbox = QVBoxLayout(self)
        dialog_vbox.addWidget(tabs)
        dialog_vbox.addLayout(Buttons(CloseButton(self)))

        # Update information
        invoke_client(None)
Example #5
0
    def show_settings_dialog(self, window, success):
        if not success:
            window.show_message(_('Server not reachable.'))
            return

        wallet = window.wallet
        d = WindowModalDialog(window, _("TrustedCoin Information"))
        d.setMinimumSize(500, 200)
        vbox = QVBoxLayout(d)
        hbox = QHBoxLayout()

        logo = QLabel()
        logo.setPixmap(QPixmap(icon_path("trustedcoin-status.png")))
        msg = _('This wallet is protected by TrustedCoin\'s two-factor authentication.') + '<br/>'\
              + _("For more information, visit") + " <a href=\"https://api.trustedcoin.com/#/electrum-help\">https://api.trustedcoin.com/#/electrum-help</a>"
        label = QLabel(msg)
        label.setOpenExternalLinks(1)

        hbox.addStretch(10)
        hbox.addWidget(logo)
        hbox.addStretch(10)
        hbox.addWidget(label)
        hbox.addStretch(10)

        vbox.addLayout(hbox)
        vbox.addStretch(10)

        msg = _(
            'TrustedCoin charges a small fee to co-sign transactions. The fee depends on how many prepaid transactions you buy. An extra output is added to your transaction every time you run out of prepaid transactions.'
        ) + '<br/>'
        label = QLabel(msg)
        label.setWordWrap(1)
        vbox.addWidget(label)

        vbox.addStretch(10)
        grid = QGridLayout()
        vbox.addLayout(grid)

        price_per_tx = wallet.price_per_tx
        n_prepay = wallet.num_prepay()
        i = 0
        for k, v in sorted(price_per_tx.items()):
            if k == 1:
                continue
            grid.addWidget(QLabel("Pay every %d transactions:" % k), i, 0)
            grid.addWidget(
                QLabel(
                    window.format_amount(v / k) + ' ' + window.base_unit() +
                    "/tx"), i, 1)
            b = QRadioButton()
            b.setChecked(k == n_prepay)
            b.clicked.connect(lambda b, k=k: self.config.set_key(
                'trustedcoin_prepay', k, True))
            grid.addWidget(b, i, 2)
            i += 1

        n = wallet.billing_info.get('tx_remaining', 0)
        grid.addWidget(
            QLabel(_("Your wallet has {} prepaid transactions.").format(n)), i,
            0)
        vbox.addLayout(Buttons(CloseButton(d)))
        d.exec_()
Example #6
0
    def __init__(self, window, plugin, keystore, device_id):
        title = _("{} Settings").format(plugin.device)
        super(CKCCSettingsDialog, self).__init__(window, title)
        self.setMaximumWidth(540)

        devmgr = plugin.device_manager()
        config = devmgr.config
        handler = keystore.handler
        self.thread = thread = keystore.thread

        def connect_and_doit():
            client = devmgr.client_by_id(device_id)
            if not client:
                raise RuntimeError("Device not connected")
            return client

        body = QWidget()
        body_layout = QVBoxLayout(body)
        grid = QGridLayout()
        grid.setColumnStretch(2, 1)

        # see <http://doc.qt.io/archives/qt-4.8/richtext-html-subset.html>
        title = QLabel('''<center>
<span style="font-size: x-large">Coldcard Wallet</span>
<br><span style="font-size: medium">from Coinkite Inc.</span>
<br><a href="https://coldcardwallet.com">coldcardwallet.com</a>''')
        title.setTextInteractionFlags(Qt.LinksAccessibleByMouse)

        grid.addWidget(title, 0, 0, 1, 2, Qt.AlignHCenter)
        y = 3

        rows = [
            ('fw_version', _("Firmware Version")),
            ('fw_built', _("Build Date")),
            ('bl_version', _("Bootloader")),
            ('xfp', _("Master Fingerprint")),
            ('serial', _("USB Serial")),
        ]
        for row_num, (member_name, label) in enumerate(rows):
            widget = QLabel('<tt>000000000000')
            widget.setTextInteractionFlags(Qt.TextSelectableByMouse
                                           | Qt.TextSelectableByKeyboard)

            grid.addWidget(QLabel(label), y, 0, 1, 1, Qt.AlignRight)
            grid.addWidget(widget, y, 1, 1, 1, Qt.AlignLeft)
            setattr(self, member_name, widget)
            y += 1
        body_layout.addLayout(grid)

        upg_btn = QPushButton('Upgrade')

        #upg_btn.setDefault(False)
        def _start_upgrade():
            thread.add(connect_and_doit, on_success=self.start_upgrade)

        upg_btn.clicked.connect(_start_upgrade)

        y += 3
        grid.addWidget(upg_btn, y, 0)
        grid.addWidget(CloseButton(self), y, 1)

        dialog_vbox = QVBoxLayout(self)
        dialog_vbox.addWidget(body)

        # Fetch values and show them
        thread.add(connect_and_doit, on_success=self.show_values)
    def __init__(self, window, plugin, keystore, device_id):
        title = _("{} Settings").format(plugin.device)
        super(SettingsDialog, self).__init__(window, title)
        self.setMaximumWidth(540)

        devmgr = plugin.device_manager()
        config = devmgr.config
        handler = keystore.handler
        thread = keystore.thread
        hs_cols, hs_rows = (128, 64)

        def invoke_client(method, *args, **kw_args):
            unpair_after = kw_args.pop('unpair_after', False)

            def task():
                client = devmgr.client_by_id(device_id)
                if not client:
                    raise RuntimeError("Device not connected")
                if method:
                    getattr(client, method)(*args, **kw_args)
                if unpair_after:
                    devmgr.unpair_id(device_id)
                return client.features

            thread.add(task, on_success=update)

        def update(features):
            self.features = features
            set_label_enabled()
            if features.bootloader_hash:
                bl_hash = bh2u(features.bootloader_hash)
                bl_hash = "\n".join([bl_hash[:32], bl_hash[32:]])
            else:
                bl_hash = "N/A"
            noyes = [_("No"), _("Yes")]
            endis = [_("Enable Passphrases"), _("Disable Passphrases")]
            disen = [_("Disabled"), _("Enabled")]
            setchange = [_("Set a PIN"), _("Change PIN")]

            version = "%d.%d.%d" % (features.major_version,
                                    features.minor_version,
                                    features.patch_version)

            device_label.setText(features.label)
            pin_set_label.setText(noyes[features.pin_protection])
            passphrases_label.setText(disen[features.passphrase_protection])
            bl_hash_label.setText(bl_hash)
            label_edit.setText(features.label)
            device_id_label.setText(features.device_id)
            initialized_label.setText(noyes[features.initialized])
            version_label.setText(version)
            clear_pin_button.setVisible(features.pin_protection)
            clear_pin_warning.setVisible(features.pin_protection)
            pin_button.setText(setchange[features.pin_protection])
            pin_msg.setVisible(not features.pin_protection)
            passphrase_button.setText(endis[features.passphrase_protection])
            language_label.setText(features.language)

        def set_label_enabled():
            label_apply.setEnabled(label_edit.text() != self.features.label)

        def rename():
            invoke_client('change_label', label_edit.text())

        def toggle_passphrase():
            title = _("Confirm Toggle Passphrase Protection")
            currently_enabled = self.features.passphrase_protection
            if currently_enabled:
                msg = _("After disabling passphrases, you can only pair this "
                        "Electrum-CHI wallet if it had an empty passphrase.  "
                        "If its passphrase was not empty, you will need to "
                        "create a new wallet with the install wizard.  You "
                        "can use this wallet again at any time by re-enabling "
                        "passphrases and entering its passphrase.")
            else:
                msg = _(
                    "Your current Electrum-CHI wallet can only be used with "
                    "an empty passphrase.  You must create a separate "
                    "wallet with the install wizard for other passphrases "
                    "as each one generates a new set of addresses.")
            msg += "\n\n" + _("Are you sure you want to proceed?")
            if not self.question(msg, title=title):
                return
            invoke_client('toggle_passphrase', unpair_after=currently_enabled)

        def change_homescreen():
            dialog = QFileDialog(self, _("Choose Homescreen"))
            filename, __ = dialog.getOpenFileName()
            if not filename:
                return  # user cancelled

            if filename.endswith('.toif'):
                img = open(filename, 'rb').read()
                if img[:8] != b'TOIf\x90\x00\x90\x00':
                    handler.show_error(
                        'File is not a TOIF file with size of 144x144')
                    return
            else:
                from PIL import Image  # FIXME
                im = Image.open(filename)
                if im.size != (128, 64):
                    handler.show_error('Image must be 128 x 64 pixels')
                    return
                im = im.convert('1')
                pix = im.load()
                img = bytearray(1024)
                for j in range(64):
                    for i in range(128):
                        if pix[i, j]:
                            o = (i + j * 128)
                            img[o // 8] |= (1 << (7 - o % 8))
                img = bytes(img)
            invoke_client('change_homescreen', img)

        def clear_homescreen():
            invoke_client('change_homescreen', b'\x00')

        def set_pin():
            invoke_client('set_pin', remove=False)

        def clear_pin():
            invoke_client('set_pin', remove=True)

        def wipe_device():
            wallet = window.wallet
            if wallet and sum(wallet.get_balance()):
                title = _("Confirm Device Wipe")
                msg = _("Are you SURE you want to wipe the device?\n"
                        "Your wallet still has CHI in it!")
                if not self.question(
                        msg, title=title, icon=QMessageBox.Critical):
                    return
            invoke_client('wipe_device', unpair_after=True)

        def slider_moved():
            mins = timeout_slider.sliderPosition()
            timeout_minutes.setText(_("{:2d} minutes").format(mins))

        def slider_released():
            config.set_session_timeout(timeout_slider.sliderPosition() * 60)

        # Information tab
        info_tab = QWidget()
        info_layout = QVBoxLayout(info_tab)
        info_glayout = QGridLayout()
        info_glayout.setColumnStretch(2, 1)
        device_label = QLabel()
        pin_set_label = QLabel()
        passphrases_label = QLabel()
        version_label = QLabel()
        device_id_label = QLabel()
        bl_hash_label = QLabel()
        bl_hash_label.setWordWrap(True)
        language_label = QLabel()
        initialized_label = QLabel()
        rows = [
            (_("Device Label"), device_label),
            (_("PIN set"), pin_set_label),
            (_("Passphrases"), passphrases_label),
            (_("Firmware Version"), version_label),
            (_("Device ID"), device_id_label),
            (_("Bootloader Hash"), bl_hash_label),
            (_("Language"), language_label),
            (_("Initialized"), initialized_label),
        ]
        for row_num, (label, widget) in enumerate(rows):
            info_glayout.addWidget(QLabel(label), row_num, 0)
            info_glayout.addWidget(widget, row_num, 1)
        info_layout.addLayout(info_glayout)

        # Settings tab
        settings_tab = QWidget()
        settings_layout = QVBoxLayout(settings_tab)
        settings_glayout = QGridLayout()

        # Settings tab - Label
        label_msg = QLabel(
            _("Name this {}.  If you have multiple devices "
              "their labels help distinguish them.").format(plugin.device))
        label_msg.setWordWrap(True)
        label_label = QLabel(_("Device Label"))
        label_edit = QLineEdit()
        label_edit.setMinimumWidth(150)
        label_edit.setMaxLength(plugin.MAX_LABEL_LEN)
        label_apply = QPushButton(_("Apply"))
        label_apply.clicked.connect(rename)
        label_edit.textChanged.connect(set_label_enabled)
        settings_glayout.addWidget(label_label, 0, 0)
        settings_glayout.addWidget(label_edit, 0, 1, 1, 2)
        settings_glayout.addWidget(label_apply, 0, 3)
        settings_glayout.addWidget(label_msg, 1, 1, 1, -1)

        # Settings tab - PIN
        pin_label = QLabel(_("PIN Protection"))
        pin_button = QPushButton()
        pin_button.clicked.connect(set_pin)
        settings_glayout.addWidget(pin_label, 2, 0)
        settings_glayout.addWidget(pin_button, 2, 1)
        pin_msg = QLabel(
            _("PIN protection is strongly recommended.  "
              "A PIN is your only protection against someone "
              "stealing your CHI if they obtain physical "
              "access to your {}.").format(plugin.device))
        pin_msg.setWordWrap(True)
        pin_msg.setStyleSheet("color: red")
        settings_glayout.addWidget(pin_msg, 3, 1, 1, -1)

        # Settings tab - Homescreen
        homescreen_label = QLabel(_("Homescreen"))
        homescreen_change_button = QPushButton(_("Change..."))
        homescreen_clear_button = QPushButton(_("Reset"))
        homescreen_change_button.clicked.connect(change_homescreen)
        try:
            import PIL
        except ImportError:
            homescreen_change_button.setDisabled(True)
            homescreen_change_button.setToolTip(
                _("Required package 'PIL' is not available - Please install it or use the Trezor website instead."
                  ))
        homescreen_clear_button.clicked.connect(clear_homescreen)
        homescreen_msg = QLabel(
            _("You can set the homescreen on your "
              "device to personalize it.  You must "
              "choose a {} x {} monochrome black and "
              "white image.").format(hs_cols, hs_rows))
        homescreen_msg.setWordWrap(True)
        settings_glayout.addWidget(homescreen_label, 4, 0)
        settings_glayout.addWidget(homescreen_change_button, 4, 1)
        settings_glayout.addWidget(homescreen_clear_button, 4, 2)
        settings_glayout.addWidget(homescreen_msg, 5, 1, 1, -1)

        # Settings tab - Session Timeout
        timeout_label = QLabel(_("Session Timeout"))
        timeout_minutes = QLabel()
        timeout_slider = QSlider(Qt.Horizontal)
        timeout_slider.setRange(1, 60)
        timeout_slider.setSingleStep(1)
        timeout_slider.setTickInterval(5)
        timeout_slider.setTickPosition(QSlider.TicksBelow)
        timeout_slider.setTracking(True)
        timeout_msg = QLabel(
            _("Clear the session after the specified period "
              "of inactivity.  Once a session has timed out, "
              "your PIN and passphrase (if enabled) must be "
              "re-entered to use the device."))
        timeout_msg.setWordWrap(True)
        timeout_slider.setSliderPosition(config.get_session_timeout() // 60)
        slider_moved()
        timeout_slider.valueChanged.connect(slider_moved)
        timeout_slider.sliderReleased.connect(slider_released)
        settings_glayout.addWidget(timeout_label, 6, 0)
        settings_glayout.addWidget(timeout_slider, 6, 1, 1, 3)
        settings_glayout.addWidget(timeout_minutes, 6, 4)
        settings_glayout.addWidget(timeout_msg, 7, 1, 1, -1)
        settings_layout.addLayout(settings_glayout)
        settings_layout.addStretch(1)

        # Advanced tab
        advanced_tab = QWidget()
        advanced_layout = QVBoxLayout(advanced_tab)
        advanced_glayout = QGridLayout()

        # Advanced tab - clear PIN
        clear_pin_button = QPushButton(_("Disable PIN"))
        clear_pin_button.clicked.connect(clear_pin)
        clear_pin_warning = QLabel(
            _("If you disable your PIN, anyone with physical access to your "
              "{} device can spend your CHI.").format(plugin.device))
        clear_pin_warning.setWordWrap(True)
        clear_pin_warning.setStyleSheet("color: red")
        advanced_glayout.addWidget(clear_pin_button, 0, 2)
        advanced_glayout.addWidget(clear_pin_warning, 1, 0, 1, 5)

        # Advanced tab - toggle passphrase protection
        passphrase_button = QPushButton()
        passphrase_button.clicked.connect(toggle_passphrase)
        passphrase_msg = WWLabel(PASSPHRASE_HELP)
        passphrase_warning = WWLabel(PASSPHRASE_NOT_PIN)
        passphrase_warning.setStyleSheet("color: red")
        advanced_glayout.addWidget(passphrase_button, 3, 2)
        advanced_glayout.addWidget(passphrase_msg, 4, 0, 1, 5)
        advanced_glayout.addWidget(passphrase_warning, 5, 0, 1, 5)

        # Advanced tab - wipe device
        wipe_device_button = QPushButton(_("Wipe Device"))
        wipe_device_button.clicked.connect(wipe_device)
        wipe_device_msg = QLabel(
            _("Wipe the device, removing all data from it.  The firmware "
              "is left unchanged."))
        wipe_device_msg.setWordWrap(True)
        wipe_device_warning = QLabel(
            _("Only wipe a device if you have the recovery seed written down "
              "and the device wallet(s) are empty, otherwise the CHI "
              "will be lost forever."))
        wipe_device_warning.setWordWrap(True)
        wipe_device_warning.setStyleSheet("color: red")
        advanced_glayout.addWidget(wipe_device_button, 6, 2)
        advanced_glayout.addWidget(wipe_device_msg, 7, 0, 1, 5)
        advanced_glayout.addWidget(wipe_device_warning, 8, 0, 1, 5)
        advanced_layout.addLayout(advanced_glayout)
        advanced_layout.addStretch(1)

        tabs = QTabWidget(self)
        tabs.addTab(info_tab, _("Information"))
        tabs.addTab(settings_tab, _("Settings"))
        tabs.addTab(advanced_tab, _("Advanced"))
        dialog_vbox = QVBoxLayout(self)
        dialog_vbox.addWidget(tabs)
        dialog_vbox.addLayout(Buttons(CloseButton(self)))

        # Update information
        invoke_client(None)
Example #8
0
    def __init__(self, main_win, outputs):
        WindowModalDialog.__init__(self, main_win, title=_("New scheduled payment"),)
        vbox = QVBoxLayout(self)
        self.setMinimumSize(400, 150)
        minute_label = HelpLabel(_('minute:'), _('''
Defines a specific minute for an hour.
Allowed characters:
"*" any value
"," value list separator
"-" range of values
"/" step values
0-59 allowed values
'''))
        hour_label = HelpLabel(_('hour:'), _('''
Defines a specific hour during the day.
Allowed characters:
"*" any value
"," value list separator
"-" range of values
"/" step values
0-23 allowed values
'''))
        day_label = HelpLabel(_('day of month:'), _('''
Defines the day number for the month.
Allowed characters:
"*" any value
"," value list separator
"-" range of values
"/" step values
0-31 allowed values
'''))
        month_label = HelpLabel(_('month:'), _('''
Defines a month during the year.
Allowed characters:
"*" any value
"," value list separator
"-" range of values
"/" step values
1-12 allowed values
'''))
        week_label = HelpLabel(_('day of week:'), _('''
Specifies the day of the week.
Allowed characters:
"*" any value
"," value list separator
"-" range of values
"/" step values
0-6 allowed values
'''))
        self.minute_edit = QLineEdit('*')
        self.minute_edit.setFixedWidth(30)
        self.minute_edit.textChanged.connect(self.update_schedule_details)
        self.hour_edit = QLineEdit('*')
        self.hour_edit.setFixedWidth(30)
        self.hour_edit.textChanged.connect(self.update_schedule_details)
        self.day_edit = QLineEdit('*')
        self.day_edit.setFixedWidth(30)
        self.day_edit.textChanged.connect(self.update_schedule_details)
        self.month_edit = QLineEdit('*')
        self.month_edit.setFixedWidth(30)
        self.month_edit.textChanged.connect(self.update_schedule_details)
        self.week_edit = QLineEdit('*')
        self.week_edit.setFixedWidth(30)
        self.week_edit.textChanged.connect(self.update_schedule_details)
        grid = QGridLayout()
        grid.addWidget(minute_label, 0, 0, alignment=Qt.AlignCenter)
        grid.addWidget(hour_label, 0, 1, alignment=Qt.AlignCenter)
        grid.addWidget(day_label, 0, 2, alignment=Qt.AlignCenter)
        grid.addWidget(month_label, 0, 3, alignment=Qt.AlignCenter)
        grid.addWidget(week_label, 0, 4, alignment=Qt.AlignCenter)
        grid.addWidget(self.minute_edit, 1, 0, alignment=Qt.AlignCenter)
        grid.addWidget(self.hour_edit, 1, 1, alignment=Qt.AlignCenter)
        grid.addWidget(self.day_edit, 1, 2, alignment=Qt.AlignCenter)
        grid.addWidget(self.month_edit, 1, 3, alignment=Qt.AlignCenter)
        grid.addWidget(self.week_edit, 1, 4, alignment=Qt.AlignCenter)
        every_day = QPushButton('every day')
        every_day.clicked.connect(lambda: self.set_as_text('0 0 * * *'))
        every_week = QPushButton('every week')
        every_week.clicked.connect(lambda: self.set_as_text('0 0 * * 0'))
        every_month = QPushButton('every month')
        every_month.clicked.connect(lambda: self.set_as_text('0 0 1 * *'))
        every_year = QPushButton('every year')
        every_year.clicked.connect(lambda: self.set_as_text('0 0 1 1 *'))
        self.schedule_details = QLabel('')
        vbox.addLayout(grid)
        vbox.addLayout(Buttons(every_day, every_week, every_month, every_year))
        vbox.addWidget(self.schedule_details)
        vbox.addStretch()
        vbox.addLayout(Buttons(CloseButton(self), OkButton(self)))
        self.update_schedule_details()
Example #9
0
    def settings_dialog(self, window):
        # hack to workaround a bug: https://github.com/spesmilo/electrum/commit/4d8fcded4b42fd673bbb61f85aa99dc329be28a4
        if self.closed:
            # if this plugin instance is supposed to be closed and we have a different newer instance available,
            # forward the call to the newer one.
            if self.parent.bwt and self.parent.bwt != self:
                self.parent.bwt.settings_dialog(window)
            return

        if not self.wallets:
            window.show_error(_('No hd wallets found.'))
            return

        d = WindowModalDialog(window, _('Connect to Bitcoin Core with bwt'))
        d.setMinimumWidth(570)
        vbox = QVBoxLayout(d)

        form = QFormLayout()
        form.setLabelAlignment(Qt.AlignRight | Qt.AlignVCenter)
        vbox.addLayout(form)

        form.addRow(title(_('Bitcoin Core settings')))

        url_e = input(self.bitcoind_url)
        form.addRow(_('RPC URL:'), url_e)

        cred_e = input(self.bitcoind_cred)
        cred_e.setPlaceholderText('<username>:<password>')
        form.addRow(_('RPC Auth:'), cred_e)
        form.addRow('', helptext(_('Leave blank to use the cookie.'), False))

        dir_e = input(self.bitcoind_dir)
        form.addRow(_('Directory:'), dir_e)
        form.addRow('', helptext(_('Used for reading the cookie file. Ignored if auth is set.'), False))

        wallet_e = input(self.bitcoind_wallet, 150)
        form.addRow(_('Wallet:'), wallet_e)
        form.addRow('', helptext(_('For use with multi-wallet. Leave blank to use the default wallet.'), False))


        form.addRow(title(_('Other settings')))

        rescan_c = QComboBox()
        rescan_c.addItems([ _('All history'), _('Since date'), _('None') ])
        rescan_c.setMaximumWidth(150)
        rescan_e = input(None, 150)
        rescan_e.setPlaceholderText('yyyy-mm-dd')
        apply_rescan(self.rescan_since, rescan_c, rescan_e)
        rescan_c.currentIndexChanged.connect(lambda i: rescan_e.setVisible(i == 1))
        rescan_l = QHBoxLayout()
        rescan_l.addWidget(rescan_c)
        rescan_l.addWidget(rescan_e)
        form.addRow(_('Scan:'), rescan_l)
        form.addRow('', helptext(_('Set to the wallet creation date to reduce scanning time.'), False))

        custom_opt_e = input(self.custom_opt)
        custom_opt_e.setPlaceholderText('e.g. --gap-limit 50 --poll-interval 1')
        form.addRow('Options', custom_opt_e)
        form.addRow('', helptext(_('Additional custom options. Optional.'), False))

        verbose_c = QComboBox()
        verbose_c.addItems([ _('info'), _('debug'), _('trace') ])
        verbose_c.setCurrentIndex(self.verbose)
        verbose_c.setMaximumWidth(150)
        form.addRow('Log level:', verbose_c)

        log_t = QTextEdit()
        log_t.setReadOnly(True)
        log_t.setFixedHeight(80)
        log_t.setStyleSheet('QTextEdit { color: #888; font-size: 0.9em }')
        log_t.setWordWrapMode(QTextOption.WrapAnywhere)
        sp = log_t.sizePolicy()
        sp.setRetainSizeWhenHidden(True)
        log_t.setSizePolicy(sp)
        log_t.hide()
        form.addRow(log_t)

        self.log_signal.connect(partial(show_log, log_t))

        def save_config_and_run():
            self.enabled = True
            self.bitcoind_url = str(url_e.text())
            self.bitcoind_dir = str(dir_e.text())
            self.bitcoind_cred = str(cred_e.text())
            self.bitcoind_wallet = str(wallet_e.text())
            self.rescan_since = get_rescan_value(rescan_c, rescan_e)
            self.custom_opt = str(custom_opt_e.text())
            self.verbose = verbose_c.currentIndex()

            self.config.set_key('bwt_enabled', self.enabled)
            self.config.set_key('bwt_bitcoind_url', self.bitcoind_url)
            self.config.set_key('bwt_bitcoind_dir', self.bitcoind_dir)
            self.config.set_key('bwt_bitcoind_cred', self.bitcoind_cred)
            self.config.set_key('bwt_bitcoind_wallet', self.bitcoind_wallet)
            self.config.set_key('bwt_rescan_since', self.rescan_since)
            self.config.set_key('bwt_custom_opt', self.custom_opt)
            self.config.set_key('bwt_verbose', self.verbose)

            log_t.clear()
            log_t.show()

            self.start()

            window.show_message(_('bwt is starting, check the logs for additional information. The bwt server will be available after Bitcoin Core completes rescanning, which may take awhile.'))
            log_t.ensureCursorVisible()

        save_b = QPushButton('Save && Connect')
        save_b.setDefault(True)
        save_b.clicked.connect(save_config_and_run)

        vbox.addLayout(Buttons(CloseButton(d), save_b))

        d.exec_()
        self.log_signal.disconnect()
Example #10
0
    def cypherseed_dialog(self, window):
        self.warn_old_revealer()

        d = WindowModalDialog(window, "Encryption Dialog")
        d.setMinimumWidth(500)
        d.setMinimumHeight(210)
        d.setMaximumHeight(450)
        d.setContentsMargins(11, 11, 1, 1)
        self.c_dialog = d

        hbox = QHBoxLayout(d)
        self.vbox = QVBoxLayout()
        logo = QLabel()
        hbox.addWidget(logo)
        logo.setPixmap(QPixmap(icon_path('revealer.png')))
        logo.setAlignment(Qt.AlignLeft)
        hbox.addSpacing(16)
        self.vbox.addWidget(
            WWLabel("<b>" + _("Revealer Visual Cryptography Plugin") +
                    "</b><br><br>" +
                    _("Ready to encrypt for revealer {}").format(
                        self.versioned_seed.version + '_' +
                        self.versioned_seed.checksum)))
        self.vbox.addSpacing(11)
        hbox.addLayout(self.vbox)
        grid = QGridLayout()
        self.vbox.addLayout(grid)

        cprint = QPushButton(_("Encrypt {}'s seed").format(self.wallet_name))
        cprint.setMaximumWidth(250)
        cprint.clicked.connect(partial(self.seed_img, True))
        self.vbox.addWidget(cprint)
        self.vbox.addSpacing(1)
        self.vbox.addWidget(
            WWLabel("<b>" + _("OR") + "</b> " +
                    _("type a custom alphanumerical secret below:")))
        self.text = ScanQRTextEdit(config=self.config)
        self.text.setTabChangesFocus(True)
        self.text.setMaximumHeight(70)
        self.text.textChanged.connect(self.customtxt_limits)
        self.vbox.addWidget(self.text)
        self.char_count = WWLabel("")
        self.char_count.setAlignment(Qt.AlignRight)
        self.vbox.addWidget(self.char_count)
        self.max_chars = WWLabel(
            "<font color='red'>" +
            _("This version supports a maximum of {} characters.").format(
                self.MAX_PLAINTEXT_LEN) + "</font>")
        self.vbox.addWidget(self.max_chars)
        self.max_chars.setVisible(False)
        self.ctext = QPushButton(_("Encrypt custom secret"))
        self.ctext.clicked.connect(self.t)
        self.vbox.addWidget(self.ctext)
        self.ctext.setEnabled(False)
        self.vbox.addSpacing(11)
        self.vbox.addLayout(Buttons(CloseButton(d)))
        self.vbox.addWidget(
            QLabel("<br>" + "<b>" + _("Warning ") + "</b>: " + _(
                "each Revealer is a one-time-pad, use it for a single secret.")
                   ))
        return bool(d.exec_())
Example #11
0
def create_settings_window(small_window):
    window = get_parent_main_window(small_window)

    d = WindowModalDialog(window, _("Bitpost settings"))
    vbox = QVBoxLayout(d)

    d.setMinimumSize(500, 200)

    hbox_maxfee = QHBoxLayout()
    hbox_maxfee.addWidget(QLabel("Default max fee to use"))
    max_fees_e = QLineEdit()
    max_fees_e.setText(str(window.config.get('bitpost_max_fee')))
    hbox_maxfee.addWidget(max_fees_e)

    fee_combo = QComboBox()
    fee_combo_values = get_fee_units(window,
                                     window.config.get('bitpost_max_fee_unit'))

    fee_combo.addItems(fee_combo_values)
    hbox_maxfee.addWidget(fee_combo)

    help_button__max_fee = QPushButton("?")
    help_button__max_fee.clicked.connect(
        lambda: d.show_message(HelpTexts.max_fee))
    hbox_maxfee.addWidget(help_button__max_fee)

    vbox.addLayout(hbox_maxfee)

    empty_line = QHBoxLayout()
    empty_line.addWidget(QLabel(""))
    vbox.addLayout(empty_line)

    advanced_settings_title = QHBoxLayout()
    advanced_settings_title.addStretch()
    advanced_settings_title.addWidget(QLabel("<b>Notifications</b>"))
    advanced_settings_title.addStretch()
    vbox.addLayout(advanced_settings_title)

    telegram_reminder = QLabel(
        _("<b>Remember to start <a href='https:/t.me/bitpostbot'>@BitpostBot</a></b>"
          ))
    telegram_reminder.setVisible(True if window.config.get(
        'bitpost_notification_platform') == 'Telegram' else False)
    telegram_reminder.setOpenExternalLinks(True)

    platform_address = QHBoxLayout()
    platform_address.addWidget(QLabel("Platform"))
    platform_combo = QComboBox()
    fee_combo_values = ['None', 'Email', 'Twitter', 'Telegram']
    platform_combo.addItems(fee_combo_values)
    platform_combo.setCurrentText(
        window.config.get('bitpost_notification_platform'))
    platform_combo.currentTextChanged.connect(
        lambda: telegram_reminder.setVisible(True) if platform_combo.
        currentText() == 'Telegram' else telegram_reminder.setVisible(False))

    platform_address.addWidget(platform_combo)

    platform_address.addWidget(QLabel("Address/handle"))
    vbox.addLayout(platform_address)
    address_input = QLineEdit()
    address_input.setText(window.config.get('bitpost_notification_address',
                                            ''))
    platform_address.addWidget(address_input)

    vbox.addWidget(telegram_reminder)

    subscription_title = QHBoxLayout()
    subscription_title.addWidget(QLabel("Subscriptions"))
    subscriptions_help = QPushButton("?")
    subscriptions_help.clicked.connect(
        lambda: d.show_message(HelpTexts.subscriptions))
    subscription_title.addWidget(subscriptions_help)
    subscription_title.addStretch()
    vbox.addLayout(subscription_title)

    subscriptions = {
        subscription['name']
        for subscription in window.config.get(
            'bitpost_notification_subscriptions')
    }
    subscriptions1 = QVBoxLayout()
    overdue_checkbox = QCheckBox("Overdue")
    if 'overdue' in subscriptions:
        overdue_checkbox.setChecked(True)
    subscriptions1.addWidget(overdue_checkbox)

    mined_checkbox = QCheckBox("Mined")
    if 'mine' in subscriptions:
        mined_checkbox.setChecked(True)
    subscriptions1.addWidget(mined_checkbox)
    max_fee_reached_checkbox = QCheckBox("Maximum fee reached")
    if 'reached' in subscriptions:
        max_fee_reached_checkbox.setChecked(True)
    subscriptions1.addWidget(max_fee_reached_checkbox)
    vbox.addLayout(subscriptions1)

    reorg_checkbox = QCheckBox("Block reorganization")
    if 'orphaned_block' in subscriptions:
        reorg_checkbox.setChecked(True)
    subscriptions1.addWidget(reorg_checkbox)
    orphaned_checkbox = QCheckBox("Child transaction orphaned")
    if '' in subscriptions:
        orphaned_checkbox.setChecked(True)
    subscriptions1.addWidget(orphaned_checkbox)

    advanced_settings_title = QHBoxLayout()
    advanced_settings_title.addStretch()
    advanced_settings_title.addWidget(QLabel("<b>Advanced Settings</b>"))
    advanced_settings_title.addStretch()
    vbox.addLayout(advanced_settings_title)

    hbox_ntx = QHBoxLayout()
    hbox_ntx.addWidget(QLabel("Default number of Txs"))
    num_txs_e = QLineEdit()
    num_txs_e.setText(str(window.config.get('bitpost_num_txs')))
    hbox_ntx.addWidget(num_txs_e)
    help_button__num_txs = QPushButton("?")
    help_button__num_txs.clicked.connect(
        lambda: d.show_message(HelpTexts.num_txs))
    hbox_ntx.addWidget(help_button__num_txs)
    vbox.addLayout(hbox_ntx)

    broadcast_policy = QHBoxLayout()
    broadcast_policy.addWidget(QLabel("First broadcast policy"))

    broadcast_policy_combo = QComboBox()
    # 'Broadcast lowest fee transaction immediatly'
    broadcast_policy_options = [
        'Don\'t delay first broadcast', 'Allow delay of first broadcast'
    ]
    if window.config.get('bitpost_delay') == 1:
        broadcast_policy_options.reverse()

    broadcast_policy_combo.addItems(broadcast_policy_options)
    broadcast_policy.addWidget(broadcast_policy_combo)

    help_button__broadcast_policy = QPushButton("?")
    help_button__broadcast_policy.clicked.connect(
        lambda: d.show_message(HelpTexts.delay))
    broadcast_policy.addWidget(help_button__broadcast_policy)
    vbox.addLayout(broadcast_policy)

    vbox.addStretch()
    vbox.addLayout(Buttons(CloseButton(d), OkButton(d)))

    if not d.exec_():
        return

    window.config.set_key('bitpost_max_fee_unit', fee_combo.currentText())
    delay = 1 if broadcast_policy_combo.currentText(
    ) == 'Allow delay of first broadcast' else 0
    window.config.set_key('bitpost_delay', delay)
    platform_text = platform_combo.currentText()

    window.config.set_key('bitpost_notification_platform', platform_text)

    subscriptions = []
    if overdue_checkbox.isChecked():
        subscriptions.append({'name': 'overdue'})
    if mined_checkbox.isChecked():
        subscriptions.append({'name': 'mine'})
    if max_fee_reached_checkbox.isChecked():
        subscriptions.append({'name': 'reached'})
    if reorg_checkbox.isChecked():
        subscriptions.append({'name': 'orphaned_block'})
    if orphaned_checkbox.isChecked():
        pass  # TODO
    window.config.set_key('bitpost_notification_subscriptions', subscriptions)

    try:
        window.config.set_key('bitpost_max_fee', float(max_fees_e.text()))
    except:
        d.show_error('Invalid maximum fee, must be a number.')
        create_settings_window(small_window)

    try:
        window.config.set_key('bitpost_num_txs', int(num_txs_e.text()))
    except:
        d.show_error(
            'Invalid default number of transactions, must be an integer')
        create_settings_window(small_window)

    if not valid_address(platform_combo.currentText(), address_input.text()):
        d.show_error('Invalid handle/address for ' +
                     platform_combo.currentText())
        create_settings_window(small_window)

    window.config.set_key('bitpost_notification_address', address_input.text())