diff --git a/electrum/gui/qml/components/NewWalletWizard.qml b/electrum/gui/qml/components/NewWalletWizard.qml new file mode 100644 index 000000000..3eec5b7b8 --- /dev/null +++ b/electrum/gui/qml/components/NewWalletWizard.qml @@ -0,0 +1,190 @@ +import QtQuick 2.6 +import QtQuick.Layouts 1.0 +import QtQuick.Controls 2.1 + +Dialog { + id: walletwizard + + title: qsTr('New Wallet') + modal: true + + enter: null // disable transition + + property var wizard_data + + function _setWizardData(wdata) { + wizard_data = {} + Object.assign(wizard_data, wdata) // deep copy + console.log('wizard data is now :' + JSON.stringify(wizard_data)) + } + + // helper function to dynamically load wizard page components + // and add them to the SwipeView + // Here we do some manual binding of page.valid -> pages.pagevalid + // to propagate the state without the binding going stale + function _loadNextComponent(comp, wdata={}) { + var page = comp.createObject(pages, { + 'visible': Qt.binding(function() { + return pages.currentItem === this + }) + }) + page.validChanged.connect(function() { + pages.pagevalid = page.valid + } ) + page.lastChanged.connect(function() { + pages.lastpage = page.last + } ) + Object.assign(page.wizard_data, wdata) // deep copy + pages.pagevalid = page.valid + + return page + } + + // State transition functions. These functions are called when the 'Next' + // button is pressed. They take data from the component, add it to the + // wizard_data object, and depending on the data create the next page + // in the conversation. + + function walletnameDone(d) { + console.log('wallet name done') + wizard_data['wallet_name'] = pages.currentItem.wallet_name + var page = _loadNextComponent(components.wallettype, wizard_data) + page.next.connect(function() {wallettypeDone()}) + } + + function wallettypeDone(d) { + console.log('wallet type done') + wizard_data['wallet_type'] = pages.currentItem.wallet_type + var page = _loadNextComponent(components.keystore, wizard_data) + page.next.connect(function() {keystoretypeDone()}) + } + + function keystoretypeDone(d) { + console.log('keystore type done') + wizard_data['keystore_type'] = pages.currentItem.keystore_type + var page + switch(wizard_data['keystore_type']) { + case 'createseed': + page = _loadNextComponent(components.createseed, wizard_data) + page.next.connect(function() {createseedDone()}) + break + case 'haveseed': + page = _loadNextComponent(components.haveseed, wizard_data) + page.next.connect(function() {haveseedDone()}) + break +// case 'masterkey' +// case 'hardware' + } + } + + function createseedDone(d) { + console.log('create seed done') + wizard_data['seed'] = pages.currentItem.seed + var page = _loadNextComponent(components.confirmseed, wizard_data) + page.next.connect(function() {confirmseedDone()}) + } + + function confirmseedDone(d) { + console.log('confirm seed done') + var page = _loadNextComponent(components.walletpassword, wizard_data) + page.next.connect(function() {walletpasswordDone()}) + page.last = true + } + + function haveseedDone(d) { + console.log('have seed done') + wizard_data['seed'] = pages.currentItem.seed + var page = _loadNextComponent(components.walletpassword, wizard_data) + page.next.connect(function() {walletpasswordDone()}) + page.last = true + } + + function walletpasswordDone(d) { + console.log('walletpassword done') + wizard_data['password'] = pages.currentItem.password + wizard_data['encrypt'] = pages.currentItem.encrypt + var page = _loadNextComponent(components.walletpassword, wizard_data) + } + + + ColumnLayout { + anchors.fill: parent + + SwipeView { + id: pages + Layout.fillHeight: true + interactive: false + + function prev() { + currentIndex = currentIndex - 1 + _setWizardData(pages.contentChildren[currentIndex].wizard_data) + pages.pagevalid = pages.contentChildren[currentIndex].valid + pages.contentChildren[currentIndex+1].destroy() + } + + function next() { + currentItem.next() + currentIndex = currentIndex + 1 + } + + function finalize() { + walletwizard.accept() + } + + property bool pagevalid: false + property bool lastpage: false + + Component.onCompleted: { + _setWizardData({}) + var start = _loadNextComponent(components.walletname) + start.next.connect(function() {walletnameDone()}) + } + + } + + PageIndicator { + id: indicator + + Layout.alignment: Qt.AlignHCenter + + count: pages.count + currentIndex: pages.currentIndex + } + + RowLayout { + Layout.alignment: Qt.AlignHCenter + Button { + visible: pages.currentIndex == 0 + text: qsTr("Cancel") + onClicked: walletwizard.close() + } + + Button { + visible: pages.currentIndex > 0 + text: qsTr('Back') + onClicked: pages.prev() + } + + Button { + text: "Next" + visible: !pages.lastpage + enabled: pages.pagevalid + onClicked: pages.next() + } + + Button { + text: "Create" + visible: pages.lastpage + enabled: pages.pagevalid + onClicked: pages.finalize() + } + + } + } + + WizardComponents { + id: components + } + +} + diff --git a/electrum/gui/qml/components/WizardComponent.qml b/electrum/gui/qml/components/WizardComponent.qml new file mode 100644 index 000000000..a07885259 --- /dev/null +++ b/electrum/gui/qml/components/WizardComponent.qml @@ -0,0 +1,10 @@ +import QtQuick 2.0 + +Item { + signal next + property var wizard_data : ({}) + property bool valid + property bool last: false +// onValidChanged: console.log('valid change in component itself') +// onWizard_dataChanged: console.log('wizard data changed in ') +} diff --git a/electrum/gui/qml/components/WizardComponents.qml b/electrum/gui/qml/components/WizardComponents.qml new file mode 100644 index 000000000..6bacca682 --- /dev/null +++ b/electrum/gui/qml/components/WizardComponents.qml @@ -0,0 +1,205 @@ +import QtQuick 2.6 +import QtQuick.Layouts 1.0 +import QtQuick.Controls 2.1 + +Item { + property Component walletname: Component { + WizardComponent { + valid: wallet_name.text.length > 0 + property alias wallet_name: wallet_name.text + GridLayout { + columns: 1 + Label { text: qsTr('Wallet name') } + TextField { + id: wallet_name + } + } + } + } + + property Component wallettype: Component { + WizardComponent { + valid: wallettypegroup.checkedButton !== null + property string wallet_type + + ButtonGroup { + id: wallettypegroup + onCheckedButtonChanged: { + wallet_type = checkedButton.wallettype + } + } + + 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') + } + } + } + } + + property Component keystore: Component { + WizardComponent { + valid: keystoregroup.checkedButton !== null + property string keystore_type + + ButtonGroup { + id: keystoregroup + onCheckedButtonChanged: { + keystore_type = checkedButton.keystoretype + } + } + + 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') + } + } + } + + } + + property Component createseed: Component { + WizardComponent { + valid: true + property alias seed: seedtext.text + property alias extend: extendcb.checked + GridLayout { + columns: 1 + Label { text: qsTr('Generating seed') } + TextArea { + id: seedtext + text: 'test this is a fake seed as you might expect' + readOnly: true + Layout.fillWidth: true + wrapMode: TextInput.WordWrap + } + CheckBox { + id: extendcb + text: qsTr('Extend seed with custom words') + } + } + } + } + + property Component haveseed: Component { + WizardComponent { + valid: true + property alias seed: seedtext.text + property alias extend: extendcb.checked + property alias bip39: bip39cb.checked + GridLayout { + columns: 1 + Label { text: qsTr('Enter your seed') } + TextArea { + id: seedtext + wrapMode: TextInput.WordWrap + Layout.fillWidth: true + } + CheckBox { + id: extendcb + enabled: true + text: qsTr('Extend seed with custom words') + } + CheckBox { + id: bip39cb + enabled: true + text: qsTr('BIP39') + } + } + } + } + + property Component confirmseed: Component { + WizardComponent { + valid: confirm.text !== '' + Layout.fillWidth: true + + GridLayout { + Layout.fillWidth: true + columns: 1 + Label { text: qsTr('Confirm your seed (re-enter)') } + TextArea { + id: confirm + wrapMode: TextInput.WordWrap + Layout.fillWidth: true + onTextChanged: { + console.log("TODO: verify seed") + } + } + } + } + } + + property Component walletpassword: Component { + WizardComponent { + valid: password1.text === password2.text + + property alias password: password1.text + property alias 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/landing.qml b/electrum/gui/qml/components/landing.qml index 73f3fcf5c..55c32c145 100644 --- a/electrum/gui/qml/components/landing.qml +++ b/electrum/gui/qml/components/landing.qml @@ -1,8 +1,10 @@ import QtQuick 2.6 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.3 import QtQml 2.6 Item { + id: rootItem + property string title: 'Network' property QtObject menu: Menu { @@ -28,7 +30,30 @@ Item { onClicked: app.stack.push(Qt.resolvedUrl('History.qml')) } + Button { + text: 'Create Wallet' + onClicked: { + var dialog = newWalletWizard.createObject(rootItem) + dialog.open() + } + } + } + Component { + id: newWalletWizard + NewWalletWizard { + parent: Overlay.overlay + x: 12 + y: 12 + width: parent.width - 24 + height: parent.height - 24 + + Overlay.modal: Rectangle { + color: "#aa000000" + } + + } + } }