aboutsummaryrefslogtreecommitdiff
path: root/wizard/WizardController.qml
diff options
context:
space:
mode:
authordsc <xmrdsc@protonmail.com>2019-01-14 01:02:44 +0100
committerdsc <xmrdsc@protonmail.com>2019-02-22 03:05:27 +0100
commitf329a710295deed3c15f2acff9a519c0a70e98e1 (patch)
tree95d2b1f6b8c31826a561d74d33368c1e9ef85d42 /wizard/WizardController.qml
parent333f4aaf83bd64de02b07a56d86bbf90363e403b (diff)
downloadmonzero-gui-f329a710295deed3c15f2acff9a519c0a70e98e1.tar.gz
monzero-gui-f329a710295deed3c15f2acff9a519c0a70e98e1.tar.xz
monzero-gui-f329a710295deed3c15f2acff9a519c0a70e98e1.zip
Wizard redesign
Diffstat (limited to 'wizard/WizardController.qml')
-rw-r--r--wizard/WizardController.qml484
1 files changed, 484 insertions, 0 deletions
diff --git a/wizard/WizardController.qml b/wizard/WizardController.qml
new file mode 100644
index 00000000..75e30389
--- /dev/null
+++ b/wizard/WizardController.qml
@@ -0,0 +1,484 @@
+// Copyright (c) 2014-2019, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import QtQuick 2.7
+import QtQuick.Controls 1.4
+import QtQuick.Controls.Styles 1.4
+import QtQuick.Layouts 1.2
+import QtQuick.Dialogs 1.2
+
+import moneroComponents.Wallet 1.0
+import "../js/Wizard.js" as Wizard
+import "../js/Windows.js" as Windows
+import "../js/Utils.js" as Utils
+import "../components" as MoneroComponents
+import "../pages"
+
+Rectangle {
+ id: wizardController
+ anchors.fill: parent
+
+ signal useMoneroClicked()
+
+ function restart() {
+ wizardStateView.state = "wizardHome"
+ wizardController.walletOptionsName = defaultAccountName;
+ wizardController.walletOptionsLocation = '';
+ wizardController.walletOptionsPassword = '';
+ wizardController.walletOptionsSeed = '';
+ wizardController.walletOptionsBackup = '';
+ wizardController.walletRestoreMode = 'seed';
+ wizardController.walletOptionsRestoreHeight = 0;
+ wizardController.walletOptionsIsRecovering = false;
+ wizardController.walletOptionsIsRecoveringFromDevice = false;
+ wizardController.walletOptionsDeviceName = '';
+ wizardController.tmpWalletFilename = '';
+ wizardController.walletRestoreMode = 'seed'
+ wizardController.walletOptionsSubaddressLookahead = "";
+ wizardController.remoteNodes = {};
+ wizardController.walletOptionsIsRecoveringFromDevice = false;
+ }
+
+ property var m_wallet;
+ property alias wizardState: wizardStateView.state
+ property alias wizardStatePrevious: wizardStateView.previousView
+ property int wizardSubViewWidth: 780 * scaleRatio
+ property int wizardSubViewTopMargin: persistentSettings.customDecorations ? 90 * scaleRatio : 32 * scaleRatio
+ property bool skipModeSelection: false
+
+ // wallet variables
+ property string walletOptionsName: ''
+ property string walletOptionsLocation: ''
+ property string walletOptionsPassword: ''
+ property string walletOptionsSeed: ''
+ property string walletOptionsBackup: ''
+ property int walletOptionsRestoreHeight: 0
+ property string walletOptionsBootstrapAddress: persistentSettings.bootstrapNodeAddress
+ property bool walletOptionsRestoringFromDevice: false
+ property bool walletOptionsIsRecovering: false
+ property bool walletOptionsIsRecoveringFromDevice: false
+ property string walletOptionsSubaddressLookahead: ''
+ property string walletOptionsDeviceName: ''
+ property string tmpWalletFilename: ''
+ property var remoteNodes: ''
+
+ // language settings, updated via sidebar
+ property string language_locale: 'en_US'
+ property string language_wallet: 'English'
+ property string language_language: 'English (US)'
+
+ // recovery made (restore wallet)
+ property string walletRestoreMode: 'seed' // seed, keys, qr
+
+ property int layoutScale: {
+ if(isMobile){
+ return 0;
+ } else if(appWindow.width < 800){
+ return 1;
+ } else {
+ return 2;
+ }
+ }
+
+ Image {
+ opacity: 1.0
+ anchors.fill: parent
+ source: "../images/middlePanelBg.jpg"
+ }
+
+ Rectangle {
+ id: wizardStateView
+ property Item currentView
+ property Item previousView
+ property WizardLanguage wizardLanguageView: WizardLanguage { }
+ property WizardHome wizardHomeView: WizardHome { }
+ property WizardCreateWallet1 wizardCreateWallet1View: WizardCreateWallet1 { }
+ property WizardCreateWallet2 wizardCreateWallet2View: WizardCreateWallet2 { }
+ property WizardCreateWallet3 wizardCreateWallet3View: WizardCreateWallet3 { }
+ property WizardCreateWallet4 wizardCreateWallet4View: WizardCreateWallet4 { }
+ property WizardRestoreWallet1 wizardRestoreWallet1View: WizardRestoreWallet1 { }
+ property WizardRestoreWallet2 wizardRestoreWallet2View: WizardRestoreWallet2 { }
+ property WizardRestoreWallet3 wizardRestoreWallet3View: WizardRestoreWallet3 { }
+ property WizardRestoreWallet4 wizardRestoreWallet4View: WizardRestoreWallet4 { }
+ property WizardCreateDevice1 wizardCreateDevice1View: WizardCreateDevice1 { }
+ property WizardOpenWallet1 wizardOpenWallet1View: WizardOpenWallet1 { }
+ property WizardModeSelection wizardModeSelectionView: WizardModeSelection { }
+ property WizardModeRemoteNodeWarning wizardModeRemoteNodeWarningView: WizardModeRemoteNodeWarning { }
+ property WizardModeBootstrap wizardModeBootstrapView: WizardModeBootstrap {}
+ anchors.fill: parent
+
+ signal previousClicked;
+
+ color: "transparent"
+ state: ''
+
+ onPreviousClicked: {
+ if (previousView && previousView.viewName != null){
+ state = previousView.viewName;
+ } else {
+ state = "wizardHome";
+ }
+ }
+
+ onCurrentViewChanged: {
+ if (previousView) {
+ if (typeof previousView.onPageClosed === "function") {
+ previousView.onPageClosed();
+ }
+
+ // Combined with NumberAnimation to fade out views
+ previousView.opacity = 0;
+ }
+
+ if (currentView) {
+ stackView.replace(currentView)
+ // Calls when view is opened
+ if (typeof currentView.onPageCompleted === "function") {
+ currentView.onPageCompleted(previousView);
+ }
+
+ // Combined with NumberAnimation to fade in views
+ currentView.opacity = 1;
+ }
+
+ previousView = currentView;
+ }
+
+ states: [
+ State {
+ name: "wizardLanguage"
+ PropertyChanges { target: wizardStateView; currentView: wizardStateView.wizardLanguageView }
+ }, State {
+ name: "wizardHome"
+ PropertyChanges { target: wizardStateView; currentView: wizardStateView.wizardHomeView }
+ }, State {
+ name: "wizardCreateWallet1"
+ PropertyChanges { target: wizardStateView; currentView: wizardStateView.wizardCreateWallet1View }
+ }, State {
+ name: "wizardCreateWallet2"
+ PropertyChanges { target: wizardStateView; currentView: wizardStateView.wizardCreateWallet2View }
+ }, State {
+ name: "wizardCreateWallet3"
+ PropertyChanges { target: wizardStateView; currentView: wizardStateView.wizardCreateWallet3View }
+ }, State {
+ name: "wizardCreateWallet4"
+ PropertyChanges { target: wizardStateView; currentView: wizardStateView.wizardCreateWallet4View }
+ }, State {
+ name: "wizardRestoreWallet1"
+ PropertyChanges { target: wizardStateView; currentView: wizardStateView.wizardRestoreWallet1View }
+ }, State {
+ name: "wizardRestoreWallet2"
+ PropertyChanges { target: wizardStateView; currentView: wizardStateView.wizardRestoreWallet2View }
+ }, State {
+ name: "wizardRestoreWallet3"
+ PropertyChanges { target: wizardStateView; currentView: wizardStateView.wizardRestoreWallet3View }
+ }, State {
+ name: "wizardRestoreWallet4"
+ PropertyChanges { target: wizardStateView; currentView: wizardStateView.wizardRestoreWallet4View }
+ }, State {
+ name: "wizardCreateDevice1"
+ PropertyChanges { target: wizardStateView; currentView: wizardStateView.wizardCreateDevice1View }
+ }, State {
+ name: "wizardOpenWallet1"
+ PropertyChanges { target: wizardStateView; currentView: wizardStateView.wizardOpenWallet1View }
+ }, State {
+ name: "wizardModeSelection"
+ PropertyChanges { target: wizardStateView; currentView: wizardStateView.wizardModeSelectionView }
+ }, State {
+ name: "wizardModeRemoteNodeWarning"
+ PropertyChanges { target: wizardStateView; currentView: wizardStateView.wizardModeRemoteNodeWarningView }
+ }, State {
+ name: "wizardModeBootstrap"
+ PropertyChanges { target: wizardStateView; currentView: wizardStateView.wizardModeBootstrapView }
+ }
+ ]
+
+ StackView {
+ id: stackView
+ initialItem: wizardStateView.wizardLanguageView
+ anchors.fill: parent
+ clip: false
+
+ delegate: StackViewDelegate {
+ pushTransition: StackViewTransition {
+ PropertyAnimation {
+ target: enterItem
+ property: "x"
+ from: target.width
+ to: 0
+ duration: 300
+ easing.type: Easing.OutCubic
+ }
+ PropertyAnimation {
+ target: exitItem
+ property: "x"
+ from: 0
+ to: 0 - target.width
+ duration: 300
+ easing.type: Easing.OutCubic
+ }
+ }
+ }
+ }
+ }
+
+ //Open Wallet from file
+ FileDialog {
+ id: fileDialog
+ title: qsTr("Please choose a file") + translationManager.emptyString
+ folder: "file://" + moneroAccountsDir
+ nameFilters: [ "Wallet files (*.keys)"]
+ sidebarVisible: false
+
+ onAccepted: {
+ wizardController.openWalletFile(fileDialog.fileUrl);
+ }
+ onRejected: {
+ console.log("Canceled")
+ appWindow.viewState = "wizard";
+ }
+ }
+
+ function createWallet() {
+ // Creates wallet in a temp. location
+
+ // Always delete the wallet object before creating new - we could be stepping back from recovering wallet
+ if (typeof wizardController.m_wallet !== 'undefined') {
+ walletManager.closeWallet()
+ console.log("deleting wallet")
+ }
+
+ var tmp_wallet_filename = oshelper.temporaryFilename();
+ console.log("Creating temporary wallet", tmp_wallet_filename)
+ var nettype = appWindow.persistentSettings.nettype;
+ var kdfRounds = appWindow.persistentSettings.kdfRounds;
+ var wallet = walletManager.createWallet(tmp_wallet_filename, "", wizardController.language_wallet, nettype, kdfRounds)
+
+ wizardController.walletOptionsSeed = wallet.seed
+
+ // saving wallet in "global" object
+ // @TODO: wallet should have a property pointing to the file where it stored or loaded from
+ wizardController.m_wallet = wallet;
+ wizardController.tmpWalletFilename = tmp_wallet_filename
+ }
+
+ function writeWallet() {
+ // Save wallet files in user specified location
+ var new_wallet_filename = Wizard.createWalletPath(
+ isIOS,
+ wizardController.walletOptionsLocation,
+ wizardController.walletOptionsName);
+
+ if(isIOS) {
+ console.log("saving in ios: " + moneroAccountsDir + new_wallet_filename)
+ wizardController.m_wallet.store(moneroAccountsDir + new_wallet_filename);
+ } else {
+ console.log("saving in wizard: " + new_wallet_filename)
+ wizardController.m_wallet.store(new_wallet_filename);
+ }
+
+ // make sure temporary wallet files are deleted
+ console.log("Removing temporary wallet: " + wizardController.tmpWalletFilename)
+ oshelper.removeTemporaryWallet(wizardController.tmpWalletFilename)
+
+ // protecting wallet with password
+ m_wallet.setPassword(walletOptionsPassword);
+
+ // Store password in session to be able to use password protected functions (e.g show seed)
+ appWindow.walletPassword = walletOptionsPassword
+
+ // save to persistent settings
+ persistentSettings.language = wizardController.language_language
+ persistentSettings.locale = wizardController.language_locale
+
+ persistentSettings.account_name = wizardController.walletOptionsName
+ persistentSettings.wallet_path = new_wallet_filename
+ persistentSettings.restore_height = (isNaN(walletOptionsRestoreHeight))? 0 : walletOptionsRestoreHeight
+
+ persistentSettings.allow_background_mining = false
+ persistentSettings.is_recovering = (wizardController.walletOptionsIsRecovering === undefined) ? false : wizardController.walletOptionsIsRecovering
+ persistentSettings.is_recovering_from_device = (wizardController.walletOptionsIsRecoveringFromDevice === undefined) ? false : wizardController.walletOptionsIsRecoveringFromDevice
+ }
+
+ function createWalletFromDevice() {
+ // TODO: create wallet in temporary filename and a) move it to the path specified by user after the final
+ // page submitted or b) delete it when program closed before reaching final page
+
+ // Always delete the wallet object before creating new - we could be stepping back from recovering wallet
+ if (typeof wizardController.m_wallet !== 'undefined') {
+ walletManager.closeWallet()
+ console.log("deleting wallet")
+ }
+
+ var tmp_wallet_filename = oshelper.temporaryFilename();
+ console.log("Creating temporary wallet", tmp_wallet_filename)
+ var nettype = persistentSettings.nettype;
+ var restoreHeight = wizardController.walletOptionsRestoreHeight;
+ var subaddressLookahead = wizardController.walletOptionsSubaddressLookahead;
+ var deviceName = wizardController.walletOptionsDeviceName;
+
+ var wallet = walletManager.createWalletFromDevice(tmp_wallet_filename, "", nettype, deviceName, restoreHeight, subaddressLookahead);
+
+ var success = wallet.status === Wallet.Status_Ok;
+ if (success) {
+ wizardController.m_wallet = wallet;
+ wizardController.walletOptionsIsRecoveringFromDevice = true;
+ wizardController.tmpWalletFilename = tmp_wallet_filename;
+ wizardController.walletOptionsRestoreHeight = wizardController.m_wallet.walletCreationHeight;
+ } else {
+ console.log(wallet.errorString)
+ appWindow.showStatusMessage(qsTr(wallet.errorString), 5);
+ walletManager.closeWallet();
+ }
+ return success;
+ }
+
+ function openWallet(){
+ if (typeof wizardController.m_wallet !== 'undefined' && wizardController.m_wallet != null) {
+ walletManager.closeWallet()
+ }
+
+ fileDialog.open();
+ }
+
+ function openWalletFile(fn) {
+ persistentSettings.restore_height = 0;
+ persistentSettings.is_recovering = false;
+
+ appWindow.restoreHeight = 0;
+ appWindow.walletPassword = "";
+
+ if(typeof fn == 'object')
+ persistentSettings.wallet_path = walletManager.urlToLocalPath(fn);
+ else
+ persistentSettings.wallet_path = fn;
+
+ if(isIOS)
+ persistentSettings.wallet_path = persistentSettings.wallet_path.replace(moneroAccountsDir, "");
+
+ console.log(moneroAccountsDir);
+ console.log(fn);
+ console.log(persistentSettings.wallet_path);
+
+ passwordDialog.onAcceptedCallback = function() {
+ walletPassword = passwordDialog.password;
+ appWindow.initialize();
+ }
+ passwordDialog.onRejectedCallback = function() {
+ console.log("Canceled");
+ appWindow.viewState = "wizard";
+ }
+
+ passwordDialog.open(appWindow.usefulName(appWindow.walletPath()));
+ }
+
+ function fetchRemoteNodes(cb, cb_err){
+ // Fetch remote nodes, parse JSON, store in result `wizardController.remoteNodes`, call setAutNode(), call callback
+ var url = appWindow.remoteNodeService + 'api/nodes.json';
+ console.log("HTTP request: " + url);
+
+ var xhr = new XMLHttpRequest();
+ xhr.timeout = 3500;
+
+ // Unfortunately we cannot spoof User-Agent since it is hardcoded in Qt
+ //xhr.setRequestHeader("User-Agent", "-");
+
+ xhr.onreadystatechange = function() {
+ var msg;
+ if (xhr.readyState != 4) {
+ return;
+ } else if(xhr.status != 200){
+ msg = "Error fetching remote nodes; status code was not 200";
+ console.log(msg);
+ if(typeof cb_err === 'function')
+ return cb_err(msg);
+ } else {
+ var body = xhr.responseText;
+ if(typeof body === 'undefined' || body === ''){
+ msg = "Error fetching remote nodes; response body was empty";
+ console.log(msg);
+ if(typeof cb_err === 'function')
+ return cb_err(msg);
+ }
+
+ var data = JSON.parse(body);
+ wizardController.remoteNodes = data;
+ console.log("node list updated");
+ setAutoNode();
+ return cb();
+ }
+ }
+
+ xhr.open('GET', url, true);
+ xhr.send(null);
+ }
+
+ function setAutoNode(){
+ var node;
+ var nodes;
+ var nodeObject = wizardController.remoteNodes;
+ var region = persistentSettings.remoteNodeRegion;
+
+ if(typeof region !== 'undefined' && region !== ""){
+ if(nodeObject.hasOwnProperty(region) && nodeObject[region].length > 0){
+ nodes = nodeObject[region];
+ } else {
+ console.log("No suitable nodes found for region " + region + ". Defaulting to random node.");
+ }
+ }
+
+ if(typeof nodes === 'undefined'){
+ nodes = [];
+ Object.keys(nodeObject).forEach(function(obj, i){
+ nodes = nodes.concat(nodeObject[obj]);
+ });
+ }
+
+ // 18089 has precedence
+ var filteredNodes = Utils.filterNodes(nodes, "18089");
+ if(filteredNodes.length > 0){
+ node = Utils.randomChoice(filteredNodes);
+ console.log('Choosing remote node \''+ node +'\' from a list of ' + filteredNodes.length);
+ } else if(nodes.length > 0){
+ node = Utils.randomChoice(nodes);
+ console.log('Choosing remote node \''+ node +'\' from a list of ' + nodes.length);
+ } else {
+ console.log("No suitable nodes found.")
+ return ''
+ }
+
+ if(appWindow.walletMode === 0)
+ persistentSettings.remoteNodeAddress = node;
+ else if(appWindow.walletMode === 1)
+ persistentSettings.bootstrapNodeAddress = node;
+ }
+
+ Component.onCompleted: {
+ //
+ }
+}