From bbd0ff8b91fd3cb8526154ccb597ca70dfa49f0f Mon Sep 17 00:00:00 2001 From: Sander van Grieken Date: Fri, 11 Mar 2022 15:44:08 +0100 Subject: [PATCH] move wizard components to separate files, add initial bip39 refine page --- .../gui/qml/components/NewWalletWizard.qml | 14 + .../qml/components/ServerConnectWizard.qml | 170 +------- .../gui/qml/components/WizardComponents.qml | 407 +----------------- .../qml/components/wizard/WCAutoConnect.qml | 40 ++ .../qml/components/wizard/WCBIP39Refine.qml | 80 ++++ .../qml/components/wizard/WCConfirmSeed.qml | 59 +++ .../qml/components/wizard/WCCreateSeed.qml | 88 ++++ .../gui/qml/components/wizard/WCHaveSeed.qml | 151 +++++++ .../qml/components/wizard/WCKeystoreType.qml | 43 ++ .../qml/components/wizard/WCProxyConfig.qml | 94 ++++ .../qml/components/wizard/WCServerConfig.qml | 42 ++ .../qml/components/wizard/WCWalletName.qml | 18 + .../components/wizard/WCWalletPassword.qml | 29 ++ .../qml/components/wizard/WCWalletType.qml | 43 ++ .../qml/components/{ => wizard}/Wizard.qml | 2 +- .../{ => wizard}/WizardComponent.qml | 0 electrum/gui/qml/qebitcoin.py | 1 - 17 files changed, 719 insertions(+), 562 deletions(-) create mode 100644 electrum/gui/qml/components/wizard/WCAutoConnect.qml create mode 100644 electrum/gui/qml/components/wizard/WCBIP39Refine.qml create mode 100644 electrum/gui/qml/components/wizard/WCConfirmSeed.qml create mode 100644 electrum/gui/qml/components/wizard/WCCreateSeed.qml create mode 100644 electrum/gui/qml/components/wizard/WCHaveSeed.qml create mode 100644 electrum/gui/qml/components/wizard/WCKeystoreType.qml create mode 100644 electrum/gui/qml/components/wizard/WCProxyConfig.qml create mode 100644 electrum/gui/qml/components/wizard/WCServerConfig.qml create mode 100644 electrum/gui/qml/components/wizard/WCWalletName.qml create mode 100644 electrum/gui/qml/components/wizard/WCWalletPassword.qml create mode 100644 electrum/gui/qml/components/wizard/WCWalletType.qml rename electrum/gui/qml/components/{ => wizard}/Wizard.qml (98%) rename electrum/gui/qml/components/{ => wizard}/WizardComponent.qml (100%) diff --git a/electrum/gui/qml/components/NewWalletWizard.qml b/electrum/gui/qml/components/NewWalletWizard.qml index 37365ba8c..3a82c5918 100644 --- a/electrum/gui/qml/components/NewWalletWizard.qml +++ b/electrum/gui/qml/components/NewWalletWizard.qml @@ -4,6 +4,8 @@ import QtQuick.Controls 2.1 import org.electrum 1.0 +import "wizard" + Wizard { id: walletwizard @@ -63,6 +65,18 @@ Wizard { function haveseedDone(d) { console.log('have seed done') + if (wizard_data['seed_type'] == 'bip39') { + var page = _loadNextComponent(components.bip39refine, wizard_data) + page.next.connect(function() {bip39refineDone()}) + } else { + var page = _loadNextComponent(components.walletpassword, wizard_data) + page.next.connect(function() {walletpasswordDone()}) + page.last = true + } + } + + function bip39refineDone(d) { + console.log('bip39 refine done') var page = _loadNextComponent(components.walletpassword, wizard_data) page.next.connect(function() {walletpasswordDone()}) page.last = true diff --git a/electrum/gui/qml/components/ServerConnectWizard.qml b/electrum/gui/qml/components/ServerConnectWizard.qml index d29b484df..0f80d47c7 100644 --- a/electrum/gui/qml/components/ServerConnectWizard.qml +++ b/electrum/gui/qml/components/ServerConnectWizard.qml @@ -2,6 +2,8 @@ import QtQuick 2.6 import QtQuick.Layouts 1.0 import QtQuick.Controls 2.3 +import "wizard" + Wizard { id: serverconnectwizard @@ -37,177 +39,15 @@ Wizard { } property Component autoconnect: Component { - WizardComponent { - valid: true - last: serverconnectgroup.checkedButton.connecttype === 'auto' - - onAccept: { - wizard_data['autoconnect'] = serverconnectgroup.checkedButton.connecttype === 'auto' - } - - ColumnLayout { - width: parent.width - - InfoTextArea { - text: qsTr('Electrum communicates with remote servers to get information about your transactions and addresses. The servers all fulfill the same purpose only differing in hardware. In most cases you simply want to let Electrum pick one at random. However if you prefer feel free to select a server manually.') - Layout.fillWidth: true - } - - ButtonGroup { - id: serverconnectgroup - } - - RadioButton { - ButtonGroup.group: serverconnectgroup - property string connecttype: 'auto' - text: qsTr('Auto connect') - } - RadioButton { - ButtonGroup.group: serverconnectgroup - property string connecttype: 'manual' - checked: true - text: qsTr('Select servers manually') - } - - } - - } + WCAutoConnect {} } property Component proxyconfig: Component { - WizardComponent { - valid: true - - onAccept: { - var p = {} - p['enabled'] = proxy_enabled.checked - if (proxy_enabled.checked) { - var type = proxytype.currentValue.toLowerCase() - if (type == 'tor') - type = 'socks5' - p['mode'] = type - p['host'] = address.text - p['port'] = port.text - p['user'] = username.text - p['password'] = password.text - } - wizard_data['proxy'] = p - } - - ColumnLayout { - width: parent.width - - Label { - text: qsTr('Proxy settings') - } - - CheckBox { - id: proxy_enabled - text: qsTr('Enable Proxy') - } - - ComboBox { - id: proxytype - enabled: proxy_enabled.checked - model: ['TOR', 'SOCKS5', 'SOCKS4'] - onCurrentIndexChanged: { - if (currentIndex == 0) { - address.text = "127.0.0.1" - port.text = "9050" - } - } - } - - GridLayout { - columns: 4 - Layout.fillWidth: true - - Label { - text: qsTr("Address") - enabled: address.enabled - } - - TextField { - id: address - enabled: proxytype.enabled && proxytype.currentIndex > 0 - } - - Label { - text: qsTr("Port") - enabled: port.enabled - } - - TextField { - id: port - enabled: proxytype.enabled && proxytype.currentIndex > 0 - } - - Label { - text: qsTr("Username") - enabled: username.enabled - } - - TextField { - id: username - enabled: proxytype.enabled && proxytype.currentIndex > 0 - } - - Label { - text: qsTr("Password") - enabled: password.enabled - } - - TextField { - id: password - enabled: proxytype.enabled && proxytype.currentIndex > 0 - echoMode: TextInput.Password - } - } - } - - } + WCProxyConfig {} } property Component serverconfig: Component { - WizardComponent { - valid: true - last: true - - onAccept: { - wizard_data['oneserver'] = !auto_server.checked - wizard_data['server'] = address.text - } - - ColumnLayout { - width: parent.width - - Label { - text: qsTr('Server settings') - } - - CheckBox { - id: auto_server - text: qsTr('Select server automatically') - checked: true - } - - GridLayout { - columns: 2 - Layout.fillWidth: true - - Label { - text: qsTr("Server") - enabled: address.enabled - } - - TextField { - id: address - enabled: !auto_server.checked - } - } - } - - } + WCServerConfig {} } } diff --git a/electrum/gui/qml/components/WizardComponents.qml b/electrum/gui/qml/components/WizardComponents.qml index 7110820ab..c6f910dad 100644 --- a/electrum/gui/qml/components/WizardComponents.qml +++ b/electrum/gui/qml/components/WizardComponents.qml @@ -5,422 +5,39 @@ import QtQuick.Controls.Material 2.0 import org.electrum 1.0 +import "wizard" + Item { property Component walletname: Component { - WizardComponent { - valid: wallet_name.text.length > 0 - - onAccept: { - wizard_data['wallet_name'] = wallet_name.text - } - - GridLayout { - columns: 1 - Label { text: qsTr('Wallet name') } - TextField { - id: wallet_name - } - } - } + WCWalletName {} } property Component wallettype: Component { - WizardComponent { - valid: wallettypegroup.checkedButton !== null - - onAccept: { - wizard_data['wallet_type'] = wallettypegroup.checkedButton.wallettype - } - - ButtonGroup { - id: wallettypegroup - } - - GridLayout { - columns: 1 - Label { text: qsTr('What kind of wallet do you want to create?') } - RadioButton { - ButtonGroup.group: wallettypegroup - property string wallettype: 'standard' - checked: true - text: qsTr('Standard Wallet') - } - RadioButton { - enabled: false - ButtonGroup.group: wallettypegroup - property string wallettype: '2fa' - text: qsTr('Wallet with two-factor authentication') - } - RadioButton { - enabled: false - ButtonGroup.group: wallettypegroup - property string wallettype: 'multisig' - text: qsTr('Multi-signature wallet') - } - RadioButton { - enabled: false - ButtonGroup.group: wallettypegroup - property string wallettype: 'import' - text: qsTr('Import Bitcoin addresses or private keys') - } - } - } + WCWalletType {} } property Component keystore: Component { - WizardComponent { - valid: keystoregroup.checkedButton !== null - - onAccept: { - wizard_data['keystore_type'] = keystoregroup.checkedButton.keystoretype - } - - ButtonGroup { - id: keystoregroup - } - - GridLayout { - columns: 1 - Label { text: qsTr('What kind of wallet do you want to create?') } - RadioButton { - ButtonGroup.group: keystoregroup - property string keystoretype: 'createseed' - checked: true - text: qsTr('Create a new seed') - } - RadioButton { - ButtonGroup.group: keystoregroup - property string keystoretype: 'haveseed' - text: qsTr('I already have a seed') - } - RadioButton { - enabled: false - ButtonGroup.group: keystoregroup - property string keystoretype: 'masterkey' - text: qsTr('Use a master key') - } - RadioButton { - enabled: false - ButtonGroup.group: keystoregroup - property string keystoretype: 'hardware' - text: qsTr('Use a hardware device') - } - } - } - + WCKeystoreType {} } property Component createseed: Component { - WizardComponent { - valid: seedtext.text != '' - - onAccept: { - wizard_data['seed'] = seedtext.text - wizard_data['seed_type'] = 'segwit' - wizard_data['seed_extend'] = extendcb.checked - wizard_data['seed_extra_words'] = extendcb.checked ? customwordstext.text : '' - } - - function setWarningText(numwords) { - var t = [ - '

', - qsTr('Please save these %1 words on paper (order is important).').arg(numwords), - qsTr('This seed will allow you to recover your wallet in case of computer failure.'), - '

', - '' + qsTr('WARNING') + ':', - '' - ] - warningtext.text = t.join(' ') - } - - Flickable { - anchors.fill: parent - contentHeight: mainLayout.height - clip:true - interactive: height < contentHeight - - GridLayout { - id: mainLayout - width: parent.width - columns: 1 - - InfoTextArea { - id: warningtext - Layout.fillWidth: true - iconStyle: InfoTextArea.IconStyle.Warn - } - Label { text: qsTr('Your wallet generation seed is:') } - SeedTextArea { - id: seedtext - readOnly: true - Layout.fillWidth: true - - BusyIndicator { - anchors.centerIn: parent - height: parent.height * 2/3 - visible: seedtext.text == '' - } - } - CheckBox { - id: extendcb - text: qsTr('Extend seed with custom words') - } - TextField { - id: customwordstext - visible: extendcb.checked - Layout.fillWidth: true - placeholderText: qsTr('Enter your custom word(s)') - echoMode: TextInput.Password - } - Component.onCompleted : { - setWarningText(12) - bitcoin.generate_seed() - } - } - } - - Bitcoin { - id: bitcoin - onGeneratedSeedChanged: { - seedtext.text = generated_seed - setWarningText(generated_seed.split(' ').length) - } - } - } + WCCreateSeed {} } property Component haveseed: Component { - WizardComponent { - id: root - valid: false - - onAccept: { - wizard_data['seed'] = seedtext.text - wizard_data['seed_type'] = bitcoin.seed_type - wizard_data['seed_extend'] = extendcb.checked - wizard_data['seed_extra_words'] = extendcb.checked ? customwordstext.text : '' - wizard_data['seed_bip39'] = seed_type.getTypeCode() == 'BIP39' - wizard_data['seed_slip39'] = seed_type.getTypeCode() == 'SLIP39' - } - - function setSeedTypeHelpText() { - var t = { - 'Electrum': [ - qsTr('Electrum seeds are the default seed type.'), - qsTr('If you are restoring from a seed previously created by Electrum, choose this option') - ].join(' '), - 'BIP39': [ - qsTr('BIP39 seeds can be imported in Electrum, so that users can access funds locked in other wallets.'), - '

', - qsTr('However, we do not generate BIP39 seeds, because they do not meet our safety standard.'), - qsTr('BIP39 seeds do not include a version number, which compromises compatibility with future software.'), - '

', - qsTr('We do not guarantee that BIP39 imports will always be supported in Electrum.') - ].join(' '), - 'SLIP39': [ - qsTr('SLIP39 seeds can be imported in Electrum, so that users can access funds locked in other wallets.'), - '

', - qsTr('However, we do not generate SLIP39 seeds.') - ].join(' ') - } - infotext.text = t[seed_type.currentText] - } - - function checkValid() { - bitcoin.verify_seed(seedtext.text, seed_type.getTypeCode() == 'BIP39', seed_type.getTypeCode() == 'SLIP39') - } - - Flickable { - anchors.fill: parent - contentHeight: mainLayout.height - clip:true - interactive: height < contentHeight - - GridLayout { - id: mainLayout - width: parent.width - columns: 2 - - Label { - text: qsTr('Seed Type') - Layout.fillWidth: true - } - ComboBox { - id: seed_type - model: ['Electrum', 'BIP39', 'SLIP39'] - onActivated: { - setSeedTypeHelpText() - checkValid() - } - function getTypeCode() { - return currentText - } - } - InfoTextArea { - id: infotext - Layout.fillWidth: true - Layout.columnSpan: 2 - } - Label { - text: qsTr('Enter your seed') - Layout.columnSpan: 2 - } - SeedTextArea { - id: seedtext - Layout.fillWidth: true - Layout.columnSpan: 2 - onTextChanged: { - validationTimer.restart() - } - - Rectangle { - anchors.fill: contentText - color: 'green' - border.color: Material.accentColor - radius: 2 - } - Label { - id: contentText - anchors.right: parent.right - anchors.bottom: parent.bottom - leftPadding: text != '' ? 16 : 0 - rightPadding: text != '' ? 16 : 0 - font.bold: false - font.pixelSize: 13 - } - } - TextArea { - id: validationtext - visible: text != '' - Layout.fillWidth: true - readOnly: true - wrapMode: TextInput.WordWrap - background: Rectangle { - color: 'transparent' - } - } - - CheckBox { - id: extendcb - Layout.columnSpan: 2 - text: qsTr('Extend seed with custom words') - } - TextField { - id: customwordstext - visible: extendcb.checked - Layout.fillWidth: true - Layout.columnSpan: 2 - placeholderText: qsTr('Enter your custom word(s)') - echoMode: TextInput.Password - } - } - } - - Bitcoin { - id: bitcoin - onSeedTypeChanged: contentText.text = bitcoin.seed_type - onSeedValidChanged: root.valid = bitcoin.seed_valid - onValidationMessageChanged: validationtext.text = bitcoin.validation_message - } - - Timer { - id: validationTimer - interval: 500 - repeat: false - onTriggered: checkValid() - } - - Component.onCompleted: { - setSeedTypeHelpText() - } - } + WCHaveSeed {} } property Component confirmseed: Component { - WizardComponent { - valid: false - - function checkValid() { - var seedvalid = confirm.text == wizard_data['seed'] - var customwordsvalid = customwordstext.text == wizard_data['seed_extra_words'] - valid = seedvalid && (wizard_data['seed_extend'] ? customwordsvalid : true) - } - - Flickable { - anchors.fill: parent - contentHeight: mainLayout.height - clip:true - interactive: height < contentHeight - - GridLayout { - id: mainLayout - width: parent.width - columns: 1 - - InfoTextArea { - Layout.fillWidth: true - text: qsTr('Your seed is important!') + ' ' + - qsTr('If you lose your seed, your money will be permanently lost.') + ' ' + - qsTr('To make sure that you have properly saved your seed, please retype it here.') - } - Label { text: qsTr('Confirm your seed (re-enter)') } - SeedTextArea { - id: confirm - Layout.fillWidth: true - onTextChanged: { - checkValid() - } - } - TextField { - id: customwordstext - Layout.fillWidth: true - placeholderText: qsTr('Enter your custom word(s)') - echoMode: TextInput.Password - onTextChanged: { - checkValid() - } - } - } - } + WCConfirmSeed {} + } - onReadyChanged: { - if (ready) - customwordstext.visible = wizard_data['seed_extend'] - } - } + property Component bip39refine: Component { + WCBIP39Refine {} } property Component walletpassword: Component { - WizardComponent { - valid: password1.text === password2.text - - onAccept: { - wizard_data['password'] = password1.text - wizard_data['encrypt'] = doencrypt.checked - } - - GridLayout { - columns: 1 - Label { text: qsTr('Password protect wallet?') } - TextField { - id: password1 - echoMode: TextInput.Password - } - TextField { - id: password2 - echoMode: TextInput.Password - } - CheckBox { - id: doencrypt - enabled: password1.text !== '' - text: qsTr('Encrypt wallet') - } - } - } + WCWalletPassword {} } diff --git a/electrum/gui/qml/components/wizard/WCAutoConnect.qml b/electrum/gui/qml/components/wizard/WCAutoConnect.qml new file mode 100644 index 000000000..c06321036 --- /dev/null +++ b/electrum/gui/qml/components/wizard/WCAutoConnect.qml @@ -0,0 +1,40 @@ +import QtQuick.Layouts 1.0 +import QtQuick.Controls 2.1 + +import ".." + +WizardComponent { + valid: true + last: serverconnectgroup.checkedButton.connecttype === 'auto' + + onAccept: { + wizard_data['autoconnect'] = serverconnectgroup.checkedButton.connecttype === 'auto' + } + + ColumnLayout { + width: parent.width + + InfoTextArea { + text: qsTr('Electrum communicates with remote servers to get information about your transactions and addresses. The servers all fulfill the same purpose only differing in hardware. In most cases you simply want to let Electrum pick one at random. However if you prefer feel free to select a server manually.') + Layout.fillWidth: true + } + + ButtonGroup { + id: serverconnectgroup + } + + RadioButton { + ButtonGroup.group: serverconnectgroup + property string connecttype: 'auto' + text: qsTr('Auto connect') + } + RadioButton { + ButtonGroup.group: serverconnectgroup + property string connecttype: 'manual' + checked: true + text: qsTr('Select servers manually') + } + + } + +} diff --git a/electrum/gui/qml/components/wizard/WCBIP39Refine.qml b/electrum/gui/qml/components/wizard/WCBIP39Refine.qml new file mode 100644 index 000000000..44b5e744e --- /dev/null +++ b/electrum/gui/qml/components/wizard/WCBIP39Refine.qml @@ -0,0 +1,80 @@ +import QtQuick 2.6 +import QtQuick.Layouts 1.0 +import QtQuick.Controls 2.1 + +import org.electrum 1.0 + +import ".." + +WizardComponent { + valid: false + + onAccept: { + } + + function setDerivationPath() { + var addrtype = { + 'p2pkh': 44, + 'p2wpkh-p2sh': 49, + 'p2wpkh': 84 + } + var nChain = Network.isTestNet ? 1 : 0 + derivationpathtext.text = + "m/" + addrtype[addresstypegroup.checkedButton.addresstype] + "'/" + + (Network.isTestNet ? 1 : 0) + "'/0'" + } + + ButtonGroup { + id: addresstypegroup + onCheckedButtonChanged: { + console.log('button changed: ' + checkedButton.addresstype) + setDerivationPath() + } + } + + Flickable { + anchors.fill: parent + contentHeight: mainLayout.height + clip:true + interactive: height < contentHeight + + GridLayout { + id: mainLayout + width: parent.width + columns: 1 + + Label { text: qsTr('Script type and Derivation path') } + Button { + text: qsTr('Detect Existing Accounts') + enabled: false + } + Label { text: qsTr('Choose the type of addresses in your wallet.') } + RadioButton { + ButtonGroup.group: addresstypegroup + property string addresstype: 'p2pkh' + text: qsTr('legacy (p2pkh)') + } + RadioButton { + ButtonGroup.group: addresstypegroup + property string addresstype: 'p2wpkh-p2sh' + text: qsTr('wrapped segwit (p2wpkh-p2sh)') + } + RadioButton { + ButtonGroup.group: addresstypegroup + property string addresstype: 'p2wpkh' + checked: true + text: qsTr('native segwit (p2wpkh)') + } + InfoTextArea { + text: qsTr('You can override the suggested derivation path.') + ' ' + + qsTr('If you are not sure what this is, leave this field unchanged.') + } + TextField { + id: derivationpathtext + Layout.fillWidth: true + placeholderText: qsTr('Derivation path') + } + } + } +} + diff --git a/electrum/gui/qml/components/wizard/WCConfirmSeed.qml b/electrum/gui/qml/components/wizard/WCConfirmSeed.qml new file mode 100644 index 000000000..5fb5b613c --- /dev/null +++ b/electrum/gui/qml/components/wizard/WCConfirmSeed.qml @@ -0,0 +1,59 @@ +import QtQuick 2.6 +import QtQuick.Layouts 1.0 +import QtQuick.Controls 2.1 + +import org.electrum 1.0 + +import ".." + +WizardComponent { + valid: false + + function checkValid() { + var seedvalid = confirm.text == wizard_data['seed'] + var customwordsvalid = customwordstext.text == wizard_data['seed_extra_words'] + valid = seedvalid && (wizard_data['seed_extend'] ? customwordsvalid : true) + } + + Flickable { + anchors.fill: parent + contentHeight: mainLayout.height + clip:true + interactive: height < contentHeight + + GridLayout { + id: mainLayout + width: parent.width + columns: 1 + + InfoTextArea { + Layout.fillWidth: true + text: qsTr('Your seed is important!') + ' ' + + qsTr('If you lose your seed, your money will be permanently lost.') + ' ' + + qsTr('To make sure that you have properly saved your seed, please retype it here.') + } + Label { text: qsTr('Confirm your seed (re-enter)') } + SeedTextArea { + id: confirm + Layout.fillWidth: true + onTextChanged: { + checkValid() + } + } + TextField { + id: customwordstext + Layout.fillWidth: true + placeholderText: qsTr('Enter your custom word(s)') + echoMode: TextInput.Password + onTextChanged: { + checkValid() + } + } + } + } + + onReadyChanged: { + if (ready) + customwordstext.visible = wizard_data['seed_extend'] + } +} diff --git a/electrum/gui/qml/components/wizard/WCCreateSeed.qml b/electrum/gui/qml/components/wizard/WCCreateSeed.qml new file mode 100644 index 000000000..d62614aab --- /dev/null +++ b/electrum/gui/qml/components/wizard/WCCreateSeed.qml @@ -0,0 +1,88 @@ +import QtQuick 2.6 +import QtQuick.Layouts 1.0 +import QtQuick.Controls 2.1 + +import org.electrum 1.0 + +import ".." + +WizardComponent { + valid: seedtext.text != '' + + onAccept: { + wizard_data['seed'] = seedtext.text + wizard_data['seed_type'] = 'segwit' + wizard_data['seed_extend'] = extendcb.checked + wizard_data['seed_extra_words'] = extendcb.checked ? customwordstext.text : '' + } + + function setWarningText(numwords) { + var t = [ + '

', + qsTr('Please save these %1 words on paper (order is important).').arg(numwords), + qsTr('This seed will allow you to recover your wallet in case of computer failure.'), + '

', + '' + qsTr('WARNING') + ':', + '' + ] + warningtext.text = t.join(' ') + } + + Flickable { + anchors.fill: parent + contentHeight: mainLayout.height + clip:true + interactive: height < contentHeight + + GridLayout { + id: mainLayout + width: parent.width + columns: 1 + + InfoTextArea { + id: warningtext + Layout.fillWidth: true + iconStyle: InfoTextArea.IconStyle.Warn + } + Label { text: qsTr('Your wallet generation seed is:') } + SeedTextArea { + id: seedtext + readOnly: true + Layout.fillWidth: true + + BusyIndicator { + anchors.centerIn: parent + height: parent.height * 2/3 + visible: seedtext.text == '' + } + } + CheckBox { + id: extendcb + text: qsTr('Extend seed with custom words') + } + TextField { + id: customwordstext + visible: extendcb.checked + Layout.fillWidth: true + placeholderText: qsTr('Enter your custom word(s)') + echoMode: TextInput.Password + } + Component.onCompleted : { + setWarningText(12) + bitcoin.generate_seed() + } + } + } + + Bitcoin { + id: bitcoin + onGeneratedSeedChanged: { + seedtext.text = generated_seed + setWarningText(generated_seed.split(' ').length) + } + } +} diff --git a/electrum/gui/qml/components/wizard/WCHaveSeed.qml b/electrum/gui/qml/components/wizard/WCHaveSeed.qml new file mode 100644 index 000000000..87df6262b --- /dev/null +++ b/electrum/gui/qml/components/wizard/WCHaveSeed.qml @@ -0,0 +1,151 @@ +import QtQuick 2.6 +import QtQuick.Layouts 1.0 +import QtQuick.Controls 2.1 +import QtQuick.Controls.Material 2.0 + +import org.electrum 1.0 + +import ".." + +WizardComponent { + id: root + valid: false + + onAccept: { + wizard_data['seed'] = seedtext.text + wizard_data['seed_type'] = bitcoin.seed_type + wizard_data['seed_extend'] = extendcb.checked + wizard_data['seed_extra_words'] = extendcb.checked ? customwordstext.text : '' + wizard_data['seed_bip39'] = seed_type.getTypeCode() == 'BIP39' + wizard_data['seed_slip39'] = seed_type.getTypeCode() == 'SLIP39' + } + + function setSeedTypeHelpText() { + var t = { + 'Electrum': [ + qsTr('Electrum seeds are the default seed type.'), + qsTr('If you are restoring from a seed previously created by Electrum, choose this option') + ].join(' '), + 'BIP39': [ + qsTr('BIP39 seeds can be imported in Electrum, so that users can access funds locked in other wallets.'), + '

', + qsTr('However, we do not generate BIP39 seeds, because they do not meet our safety standard.'), + qsTr('BIP39 seeds do not include a version number, which compromises compatibility with future software.') + ].join(' '), + 'SLIP39': [ + qsTr('SLIP39 seeds can be imported in Electrum, so that users can access funds locked in other wallets.'), + '

', + qsTr('However, we do not generate SLIP39 seeds.') + ].join(' ') + } + infotext.text = t[seed_type.currentText] + } + + function checkValid() { + bitcoin.verify_seed(seedtext.text, seed_type.getTypeCode() == 'BIP39', seed_type.getTypeCode() == 'SLIP39') + } + + Flickable { + anchors.fill: parent + contentHeight: mainLayout.height + clip:true + interactive: height < contentHeight + + GridLayout { + id: mainLayout + width: parent.width + columns: 2 + + Label { + text: qsTr('Seed Type') + Layout.fillWidth: true + } + ComboBox { + id: seed_type + model: ['Electrum', 'BIP39', 'SLIP39'] + onActivated: { + setSeedTypeHelpText() + checkValid() + } + function getTypeCode() { + return currentText + } + } + InfoTextArea { + id: infotext + Layout.fillWidth: true + Layout.columnSpan: 2 + } + Label { + text: qsTr('Enter your seed') + Layout.columnSpan: 2 + } + SeedTextArea { + id: seedtext + Layout.fillWidth: true + Layout.columnSpan: 2 + onTextChanged: { + validationTimer.restart() + } + + Rectangle { + anchors.fill: contentText + color: 'green' + border.color: Material.accentColor + radius: 2 + } + Label { + id: contentText + anchors.right: parent.right + anchors.bottom: parent.bottom + leftPadding: text != '' ? 16 : 0 + rightPadding: text != '' ? 16 : 0 + font.bold: false + font.pixelSize: 13 + } + } + TextArea { + id: validationtext + visible: text != '' + Layout.fillWidth: true + readOnly: true + wrapMode: TextInput.WordWrap + background: Rectangle { + color: 'transparent' + } + } + + CheckBox { + id: extendcb + Layout.columnSpan: 2 + text: qsTr('Extend seed with custom words') + } + TextField { + id: customwordstext + visible: extendcb.checked + Layout.fillWidth: true + Layout.columnSpan: 2 + placeholderText: qsTr('Enter your custom word(s)') + echoMode: TextInput.Password + } + } + } + + Bitcoin { + id: bitcoin + onSeedTypeChanged: contentText.text = bitcoin.seed_type + onSeedValidChanged: root.valid = bitcoin.seed_valid + onValidationMessageChanged: validationtext.text = bitcoin.validation_message + } + + Timer { + id: validationTimer + interval: 500 + repeat: false + onTriggered: checkValid() + } + + Component.onCompleted: { + setSeedTypeHelpText() + } +} diff --git a/electrum/gui/qml/components/wizard/WCKeystoreType.qml b/electrum/gui/qml/components/wizard/WCKeystoreType.qml new file mode 100644 index 000000000..2e180a640 --- /dev/null +++ b/electrum/gui/qml/components/wizard/WCKeystoreType.qml @@ -0,0 +1,43 @@ +import QtQuick.Layouts 1.0 +import QtQuick.Controls 2.1 + +WizardComponent { + valid: keystoregroup.checkedButton !== null + + onAccept: { + wizard_data['keystore_type'] = keystoregroup.checkedButton.keystoretype + } + + ButtonGroup { + id: keystoregroup + } + + GridLayout { + columns: 1 + Label { text: qsTr('What kind of wallet do you want to create?') } + RadioButton { + ButtonGroup.group: keystoregroup + property string keystoretype: 'createseed' + checked: true + text: qsTr('Create a new seed') + } + RadioButton { + ButtonGroup.group: keystoregroup + property string keystoretype: 'haveseed' + text: qsTr('I already have a seed') + } + RadioButton { + enabled: false + ButtonGroup.group: keystoregroup + property string keystoretype: 'masterkey' + text: qsTr('Use a master key') + } + RadioButton { + enabled: false + ButtonGroup.group: keystoregroup + property string keystoretype: 'hardware' + text: qsTr('Use a hardware device') + } + } +} + diff --git a/electrum/gui/qml/components/wizard/WCProxyConfig.qml b/electrum/gui/qml/components/wizard/WCProxyConfig.qml new file mode 100644 index 000000000..bf1c62b77 --- /dev/null +++ b/electrum/gui/qml/components/wizard/WCProxyConfig.qml @@ -0,0 +1,94 @@ +import QtQuick.Layouts 1.0 +import QtQuick.Controls 2.1 + +WizardComponent { + valid: true + + onAccept: { + var p = {} + p['enabled'] = proxy_enabled.checked + if (proxy_enabled.checked) { + var type = proxytype.currentValue.toLowerCase() + if (type == 'tor') + type = 'socks5' + p['mode'] = type + p['host'] = address.text + p['port'] = port.text + p['user'] = username.text + p['password'] = password.text + } + wizard_data['proxy'] = p + } + + ColumnLayout { + width: parent.width + + Label { + text: qsTr('Proxy settings') + } + + CheckBox { + id: proxy_enabled + text: qsTr('Enable Proxy') + } + + ComboBox { + id: proxytype + enabled: proxy_enabled.checked + model: ['TOR', 'SOCKS5', 'SOCKS4'] + onCurrentIndexChanged: { + if (currentIndex == 0) { + address.text = "127.0.0.1" + port.text = "9050" + } + } + } + + GridLayout { + columns: 4 + Layout.fillWidth: true + + Label { + text: qsTr("Address") + enabled: address.enabled + } + + TextField { + id: address + enabled: proxytype.enabled && proxytype.currentIndex > 0 + } + + Label { + text: qsTr("Port") + enabled: port.enabled + } + + TextField { + id: port + enabled: proxytype.enabled && proxytype.currentIndex > 0 + } + + Label { + text: qsTr("Username") + enabled: username.enabled + } + + TextField { + id: username + enabled: proxytype.enabled && proxytype.currentIndex > 0 + } + + Label { + text: qsTr("Password") + enabled: password.enabled + } + + TextField { + id: password + enabled: proxytype.enabled && proxytype.currentIndex > 0 + echoMode: TextInput.Password + } + } + } + +} diff --git a/electrum/gui/qml/components/wizard/WCServerConfig.qml b/electrum/gui/qml/components/wizard/WCServerConfig.qml new file mode 100644 index 000000000..8bad45136 --- /dev/null +++ b/electrum/gui/qml/components/wizard/WCServerConfig.qml @@ -0,0 +1,42 @@ +import QtQuick.Layouts 1.0 +import QtQuick.Controls 2.1 + +WizardComponent { + valid: true + last: true + + onAccept: { + wizard_data['oneserver'] = !auto_server.checked + wizard_data['server'] = address.text + } + + ColumnLayout { + width: parent.width + + Label { + text: qsTr('Server settings') + } + + CheckBox { + id: auto_server + text: qsTr('Select server automatically') + checked: true + } + + GridLayout { + columns: 2 + Layout.fillWidth: true + + Label { + text: qsTr("Server") + enabled: address.enabled + } + + TextField { + id: address + enabled: !auto_server.checked + } + } + } + +} diff --git a/electrum/gui/qml/components/wizard/WCWalletName.qml b/electrum/gui/qml/components/wizard/WCWalletName.qml new file mode 100644 index 000000000..c83d25fe4 --- /dev/null +++ b/electrum/gui/qml/components/wizard/WCWalletName.qml @@ -0,0 +1,18 @@ +import QtQuick.Layouts 1.0 +import QtQuick.Controls 2.1 + +WizardComponent { + valid: wallet_name.text.length > 0 + + onAccept: { + wizard_data['wallet_name'] = wallet_name.text + } + + GridLayout { + columns: 1 + Label { text: qsTr('Wallet name') } + TextField { + id: wallet_name + } + } +} diff --git a/electrum/gui/qml/components/wizard/WCWalletPassword.qml b/electrum/gui/qml/components/wizard/WCWalletPassword.qml new file mode 100644 index 000000000..9da3681ff --- /dev/null +++ b/electrum/gui/qml/components/wizard/WCWalletPassword.qml @@ -0,0 +1,29 @@ +import QtQuick.Layouts 1.0 +import QtQuick.Controls 2.1 + +WizardComponent { + valid: password1.text === password2.text + + onAccept: { + wizard_data['password'] = password1.text + wizard_data['encrypt'] = doencrypt.checked + } + + GridLayout { + columns: 1 + Label { text: qsTr('Password protect wallet?') } + TextField { + id: password1 + echoMode: TextInput.Password + } + TextField { + id: password2 + echoMode: TextInput.Password + } + CheckBox { + id: doencrypt + enabled: password1.text !== '' + text: qsTr('Encrypt wallet') + } + } +} diff --git a/electrum/gui/qml/components/wizard/WCWalletType.qml b/electrum/gui/qml/components/wizard/WCWalletType.qml new file mode 100644 index 000000000..e7c02dd61 --- /dev/null +++ b/electrum/gui/qml/components/wizard/WCWalletType.qml @@ -0,0 +1,43 @@ +import QtQuick.Layouts 1.0 +import QtQuick.Controls 2.1 + +WizardComponent { + valid: wallettypegroup.checkedButton !== null + + onAccept: { + wizard_data['wallet_type'] = wallettypegroup.checkedButton.wallettype + } + + ButtonGroup { + id: wallettypegroup + } + + GridLayout { + columns: 1 + Label { text: qsTr('What kind of wallet do you want to create?') } + RadioButton { + ButtonGroup.group: wallettypegroup + property string wallettype: 'standard' + checked: true + text: qsTr('Standard Wallet') + } + RadioButton { + enabled: false + ButtonGroup.group: wallettypegroup + property string wallettype: '2fa' + text: qsTr('Wallet with two-factor authentication') + } + RadioButton { + enabled: false + ButtonGroup.group: wallettypegroup + property string wallettype: 'multisig' + text: qsTr('Multi-signature wallet') + } + RadioButton { + enabled: false + ButtonGroup.group: wallettypegroup + property string wallettype: 'import' + text: qsTr('Import Bitcoin addresses or private keys') + } + } +} diff --git a/electrum/gui/qml/components/Wizard.qml b/electrum/gui/qml/components/wizard/Wizard.qml similarity index 98% rename from electrum/gui/qml/components/Wizard.qml rename to electrum/gui/qml/components/wizard/Wizard.qml index c7c4a23a2..c87db3c98 100644 --- a/electrum/gui/qml/components/Wizard.qml +++ b/electrum/gui/qml/components/wizard/Wizard.qml @@ -138,7 +138,7 @@ Dialog { rowSpacing: 0 Image { - source: "../../icons/electrum.png" + source: "../../../icons/electrum.png" Layout.preferredWidth: 48 Layout.preferredHeight: 48 Layout.leftMargin: 12 diff --git a/electrum/gui/qml/components/WizardComponent.qml b/electrum/gui/qml/components/wizard/WizardComponent.qml similarity index 100% rename from electrum/gui/qml/components/WizardComponent.qml rename to electrum/gui/qml/components/wizard/WizardComponent.qml diff --git a/electrum/gui/qml/qebitcoin.py b/electrum/gui/qml/qebitcoin.py index 16ed23a05..f556c7bfe 100644 --- a/electrum/gui/qml/qebitcoin.py +++ b/electrum/gui/qml/qebitcoin.py @@ -79,7 +79,6 @@ class QEBitcoin(QObject): if is_checksum: seed_type = 'bip39' seed_valid = True - seed_valid = False # for now elif slip39: # TODO: incomplete impl, this code only validates a single share. try: