move wizard components to separate files, add initial bip39 refine page
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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 {}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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 = [
|
||||
'<p>',
|
||||
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.'),
|
||||
'</p>',
|
||||
'<b>' + qsTr('WARNING') + ':</b>',
|
||||
'<ul>',
|
||||
'<li>' + qsTr('Never disclose your seed.') + '</li>',
|
||||
'<li>' + qsTr('Never type it on a website.') + '</li>',
|
||||
'<li>' + qsTr('Do not store it electronically.') + '</li>',
|
||||
'</ul>'
|
||||
]
|
||||
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.'),
|
||||
'<br/><br/>',
|
||||
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.'),
|
||||
'<br/><br/>',
|
||||
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.'),
|
||||
'<br/><br/>',
|
||||
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
|
||||
WCConfirmSeed {}
|
||||
}
|
||||
|
||||
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']
|
||||
}
|
||||
}
|
||||
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 {}
|
||||
}
|
||||
|
||||
|
||||
|
||||
40
electrum/gui/qml/components/wizard/WCAutoConnect.qml
Normal file
40
electrum/gui/qml/components/wizard/WCAutoConnect.qml
Normal file
@@ -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')
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
80
electrum/gui/qml/components/wizard/WCBIP39Refine.qml
Normal file
80
electrum/gui/qml/components/wizard/WCBIP39Refine.qml
Normal file
@@ -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')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
59
electrum/gui/qml/components/wizard/WCConfirmSeed.qml
Normal file
59
electrum/gui/qml/components/wizard/WCConfirmSeed.qml
Normal file
@@ -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']
|
||||
}
|
||||
}
|
||||
88
electrum/gui/qml/components/wizard/WCCreateSeed.qml
Normal file
88
electrum/gui/qml/components/wizard/WCCreateSeed.qml
Normal file
@@ -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 = [
|
||||
'<p>',
|
||||
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.'),
|
||||
'</p>',
|
||||
'<b>' + qsTr('WARNING') + ':</b>',
|
||||
'<ul>',
|
||||
'<li>' + qsTr('Never disclose your seed.') + '</li>',
|
||||
'<li>' + qsTr('Never type it on a website.') + '</li>',
|
||||
'<li>' + qsTr('Do not store it electronically.') + '</li>',
|
||||
'</ul>'
|
||||
]
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
151
electrum/gui/qml/components/wizard/WCHaveSeed.qml
Normal file
151
electrum/gui/qml/components/wizard/WCHaveSeed.qml
Normal file
@@ -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.'),
|
||||
'<br/><br/>',
|
||||
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.'),
|
||||
'<br/><br/>',
|
||||
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()
|
||||
}
|
||||
}
|
||||
43
electrum/gui/qml/components/wizard/WCKeystoreType.qml
Normal file
43
electrum/gui/qml/components/wizard/WCKeystoreType.qml
Normal file
@@ -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')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
94
electrum/gui/qml/components/wizard/WCProxyConfig.qml
Normal file
94
electrum/gui/qml/components/wizard/WCProxyConfig.qml
Normal file
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
42
electrum/gui/qml/components/wizard/WCServerConfig.qml
Normal file
42
electrum/gui/qml/components/wizard/WCServerConfig.qml
Normal file
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
18
electrum/gui/qml/components/wizard/WCWalletName.qml
Normal file
18
electrum/gui/qml/components/wizard/WCWalletName.qml
Normal file
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
29
electrum/gui/qml/components/wizard/WCWalletPassword.qml
Normal file
29
electrum/gui/qml/components/wizard/WCWalletPassword.qml
Normal file
@@ -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')
|
||||
}
|
||||
}
|
||||
}
|
||||
43
electrum/gui/qml/components/wizard/WCWalletType.qml
Normal file
43
electrum/gui/qml/components/wizard/WCWalletType.qml
Normal file
@@ -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')
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user