diff --git a/main.qml b/main.qml index 8e1c56fd..2a4f2af3 100644 --- a/main.qml +++ b/main.qml @@ -68,6 +68,10 @@ ApplicationWindow { property int blocksToSync: 1 property var isMobile: (appWindow.width > 700 && !isAndroid) ? false : true property var cameraUi + property bool remoteNodeConnected: false + // Default daemon addresses + readonly property string localDaemonAddress : !persistentSettings.testnet ? "localhost:18081" : "localhost:28081" + property string currentDaemonAddress; // true if wallet ever synchronized property bool walletInitialized : false @@ -164,7 +168,6 @@ ApplicationWindow { function initialize() { console.log("initializing..") - walletInitialized = false; // Use stored log level if (persistentSettings.logLevel == 5) @@ -186,7 +189,7 @@ ApplicationWindow { console.log("Daemon change - closing " + currentWallet) closeWallet(); currentWallet = undefined - } else { + } else if (!walletInitialized) { // set page to transfer if not changing daemon middlePanel.state = "Transfer"; @@ -194,7 +197,11 @@ ApplicationWindow { } - walletManager.setDaemonAddress(persistentSettings.daemon_address) + + // Local daemon settings + walletManager.setDaemonAddress(localDaemonAddress) + + // wallet already opened with wizard, we just need to initialize it if (typeof wizard.m_wallet !== 'undefined') { console.log("using wizard wallet") @@ -270,14 +277,20 @@ ApplicationWindow { middlePanel.sweepUnmixableClicked.connect(handleSweepUnmixable); middlePanel.checkPaymentClicked.connect(handleCheckPayment); - console.log("initializing with daemon address: ", persistentSettings.daemon_address) + console.log("Recovering from seed: ", persistentSettings.is_recovering) console.log("restore Height", persistentSettings.restore_height) // Use saved daemon rpc login settings - currentWallet.setDaemonLogin(persistentSettings.daemonUsername, persistentSettings.daemonPassword); + currentWallet.setDaemonLogin(persistentSettings.daemonUsername, persistentSettings.daemonPassword) + + if(persistentSettings.useRemoteNode) + currentDaemonAddress = persistentSettings.remoteNodeAddress + else + currentDaemonAddress = localDaemonAddress - currentWallet.initAsync(persistentSettings.daemon_address, 0, persistentSettings.is_recovering, persistentSettings.restore_height); + console.log("initializing with daemon address: ", currentDaemonAddress) + currentWallet.initAsync(currentDaemonAddress, 0, persistentSettings.is_recovering, persistentSettings.restore_height); } function walletPath() { @@ -302,7 +315,7 @@ ApplicationWindow { middlePanel.transferView.updatePriorityDropdown(); // If wallet isnt connected and no daemon is running - Ask - if(isDaemonLocal() && !walletInitialized && status === Wallet.ConnectionStatus_Disconnected && !daemonManager.running(persistentSettings.testnet)){ + if(!isMobile && isDaemonLocal() && !walletInitialized && status === Wallet.ConnectionStatus_Disconnected && !daemonManager.running(persistentSettings.testnet)){ daemonManagerDialog.open(); } // initialize transaction history once wallet is initialized first time; @@ -358,10 +371,25 @@ ApplicationWindow { console.log("New block found - updating history") currentWallet.history.refresh() timeToUnlock = currentWallet.history.minutesToUnlock - leftPanel.minutesToUnlockTxt = (timeToUnlock > 0)? (timeToUnlock == 20)? qsTr("Unlocked balance (waiting for block)").arg(timeToUnlock) : qsTr("Unlocked balance (~%1 min)").arg(timeToUnlock) : qsTr("Unlocked balance"); + leftPanel.minutesToUnlockTxt = (timeToUnlock > 0)? (timeToUnlock == 20)? qsTr("Unlocked balance (waiting for block)") : qsTr("Unlocked balance (~%1 min)").arg(timeToUnlock) : qsTr("Unlocked balance"); } } + function connectRemoteNode() { + console.log("connecting remote node"); + persistentSettings.useRemoteNode = true; + currentWallet.initAsync(persistentSettings.remoteNodeAddress); + remoteNodeConnected = true; + } + + function disconnectRemoteNode() { + console.log("disconnecting remote node"); + persistentSettings.useRemoteNode = false; + currentDaemonAddress = localDaemonAddress + currentWallet.initAsync(currentDaemonAddress); + remoteNodeConnected = false; + } + function onWalletRefresh() { console.log(">>> wallet refreshed") @@ -383,6 +411,29 @@ ApplicationWindow { // Update transfer page status middlePanel.updateStatus(); + // Use remote node while local daemon is syncing + if (persistentSettings.useRemoteNode) { + var localNodeConnected = walletManager.connected; + var localNodeSynced = localNodeConnected && walletManager.localDaemonSynced() + if (!currentWallet.connected() || !localNodeSynced) { + console.log("Using remote node while local node is syncing") + // Connect to remote node if not already connected + if(!remoteNodeConnected) { + connectRemoteNode(); + } + + //update local daemon sync progress bar + if(localNodeConnected) { + leftPanel.progressBar.updateProgress(walletManager.blockchainHeight(),walletManager.blockchainTargetHeight(), 0, qsTr("Remaining blocks (local node):")); + leftPanel.progressBar.visible = true + } + + // local daemon is synced - use it! + } else if (localNodeSynced && remoteNodeConnected) { + disconnectRemoteNode(); + } + } + // Refresh is succesfull if blockchain height > 1 if (currentWallet.blockChainHeight() > 1){ @@ -706,7 +757,7 @@ ApplicationWindow { ", txid: ", txid, ", txkey: ", txkey); - var result = walletManager.checkPayment(address, txid, txkey, persistentSettings.daemon_address); + var result = walletManager.checkPayment(address, txid, txkey, currentDaemonAddress); var results = result.split("|"); if (results.length < 4) { informationPopup.title = qsTr("Error") + translationManager.emptyString; @@ -892,6 +943,9 @@ ApplicationWindow { property string daemonPassword: "" property bool transferShowAdvanced: false property string blockchainDataDir: "" + property bool startLocalNode: true + property bool useRemoteNode: false + property string remoteNodeAddress: "" } // Information dialog diff --git a/pages/Mining.qml b/pages/Mining.qml index 2099a45e..0d87310f 100644 --- a/pages/Mining.qml +++ b/pages/Mining.qml @@ -37,6 +37,15 @@ Rectangle { color: "#F0EEEE" property var currentHashRate: 0 + function isDaemonLocal() { + if (appWindow.currentDaemonAddress === "") + return false + var daemonHost = appWindow.currentDaemonAddress.split(":")[0] + if (daemonHost === "127.0.0.1" || daemonHost === "localhost") + return true + return false + } + /* main layout */ ColumnLayout { id: mainLayout diff --git a/pages/Settings.qml b/pages/Settings.qml index b1d36bc9..e92c3a8c 100644 --- a/pages/Settings.qml +++ b/pages/Settings.qml @@ -38,7 +38,6 @@ import "../components" import moneroComponents.Clipboard 1.0 Rectangle { - property var daemonAddress property bool viewOnly: false id: page @@ -48,9 +47,6 @@ Rectangle { function initSettings() { //runs on every page load - - // Daemon settings - daemonAddress = persistentSettings.daemon_address.split(":"); } ColumnLayout { @@ -79,7 +75,7 @@ Rectangle { } GridLayout { - columns: (isMobile)? 2 : 4 + columns: (isMobile)? 1 : 4 StandardButton { id: closeWalletButton text: qsTr("Close wallet") + translationManager.emptyString @@ -145,6 +141,7 @@ Rectangle { */ StandardButton { id: rescanSpentButton + enabled: !persistentSettings.useRemoteNode text: qsTr("Rescan wallet balance") + translationManager.emptyString shadowReleasedColor: "#FF4304" shadowPressedColor: "#B32D00" @@ -169,16 +166,53 @@ Rectangle { } } + RowLayout { + + StandardButton { + id: remoteDisconnect + enabled: persistentSettings.useRemoteNode + Layout.fillWidth: false + text: qsTr("Local Node") + translationManager.emptyString + shadowReleasedColor: "#FF4304" + shadowPressedColor: "#B32D00" + releasedColor: "#FF6C3C" + pressedColor: "#FF4304" + onClicked: { + appWindow.disconnectRemoteNode(); + } + } + + StandardButton { + id: remoteConnect + enabled: !persistentSettings.useRemoteNode + Layout.fillWidth: false + text: qsTr("Remote Node") + translationManager.emptyString + shadowReleasedColor: "#FF4304" + shadowPressedColor: "#B32D00" + releasedColor: "#FF6C3C" + pressedColor: "#FF4304" + onClicked: { + appWindow.connectRemoteNode(); + } + } + } + //! Manage daemon RowLayout { + visible: !isMobile + Layout.topMargin: 20 Label { id: manageDaemonLabel - Layout.fillWidth: true color: "#4A4949" - text: qsTr("Manage daemon") + translationManager.emptyString - fontSize: 16 - anchors.topMargin: 30 - Layout.topMargin: 30 + text: qsTr("Manage Daemon") + translationManager.emptyString + } + + CheckBox { + id: daemonAdvanced + Layout.leftMargin: 15 + text: qsTr("Show advanced") + translationManager.emptyString + checkedIcon: "../images/checkedVioletIcon.png" + uncheckedIcon: "../images/uncheckedIcon.png" } } Rectangle { @@ -188,27 +222,28 @@ Rectangle { } GridLayout { + visible: !isMobile id: daemonStatusRow columns: (isMobile) ? 2 : 4 StandardButton { - visible: true - enabled: !appWindow.daemonRunning + visible: !appWindow.daemonRunning id: startDaemonButton - text: qsTr("Start daemon") + translationManager.emptyString + text: qsTr("Start Local Node") + translationManager.emptyString shadowReleasedColor: "#FF4304" shadowPressedColor: "#B32D00" releasedColor: "#FF6C3C" pressedColor: "#FF4304" onClicked: { + // Set current daemon address to local + appWindow.currentDaemonAddress = appWindow.localDaemonAddress appWindow.startDaemon(daemonFlags.text) } } StandardButton { - visible: true - enabled: appWindow.daemonRunning + visible: appWindow.daemonRunning id: stopDaemonButton - text: qsTr("Stop daemon") + translationManager.emptyString + text: qsTr("Stop Local Node") + translationManager.emptyString shadowReleasedColor: "#FF4304" shadowPressedColor: "#B32D00" releasedColor: "#FF6C3C" @@ -231,11 +266,11 @@ Rectangle { daemonConsolePopup.open(); } } - } - RowLayout { + ColumnLayout { id: blockchainFolderRow + visible: !isMobile Label { id: blockchainFolderLabel color: "#4A4949" @@ -262,13 +297,14 @@ Rectangle { } } + RowLayout { + visible: daemonAdvanced.checked && !isMobile id: daemonFlagsRow Label { id: daemonFlagsLabel color: "#4A4949" - text: qsTr("Daemon startup flags") + translationManager.emptyString - fontSize: 16 + text: qsTr("Local daemon startup flags") + translationManager.emptyString } LineEdit { id: daemonFlags @@ -281,59 +317,21 @@ Rectangle { RowLayout { Layout.fillWidth: true - spacing: 10 - - Label { - id: daemonAddrLabel - Layout.fillWidth: true - color: "#4A4949" - text: qsTr("Daemon address") + translationManager.emptyString - fontSize: 16 - } - } - - GridLayout { - id: daemonAddrRow - Layout.fillWidth: true - columnSpacing: 10 - columns: (isMobile) ? 2 : 3 - - LineEdit { - id: daemonAddr - Layout.preferredWidth: 100 - Layout.fillWidth: true - text: (daemonAddress !== undefined) ? daemonAddress[0] : "" - placeholderText: qsTr("Hostname / IP") + translationManager.emptyString - } - - - LineEdit { - id: daemonPort - Layout.preferredWidth: 100 - Layout.fillWidth: true - text: (daemonAddress !== undefined) ? daemonAddress[1] : "18081" - placeholderText: qsTr("Port") + translationManager.emptyString - } - } - - RowLayout { - Layout.fillWidth: true - spacing: 10 + visible: daemonAdvanced.checked || isMobile Label { id: daemonLoginLabel Layout.fillWidth: true color: "#4A4949" - text: qsTr("Login (optional)") + translationManager.emptyString - fontSize: 16 + text: qsTr("Node login (optional)") + translationManager.emptyString } } - RowLayout { - + ColumnLayout { + visible: daemonAdvanced.checked || isMobile LineEdit { id: daemonUsername - Layout.preferredWidth: 100 + Layout.preferredWidth: 100 * scaleRatio Layout.fillWidth: true text: persistentSettings.daemonUsername placeholderText: qsTr("Username") + translationManager.emptyString @@ -342,50 +340,65 @@ Rectangle { LineEdit { id: daemonPassword - Layout.preferredWidth: 100 + Layout.preferredWidth: 100 * scaleRatio Layout.fillWidth: true text: persistentSettings.daemonPassword placeholderText: qsTr("Password") + translationManager.emptyString echoMode: TextInput.Password } + } - StandardButton { - id: daemonAddrSave - Layout.fillWidth: false - Layout.leftMargin: 30 - text: qsTr("Connect") + translationManager.emptyString - shadowReleasedColor: "#FF4304" - shadowPressedColor: "#B32D00" - releasedColor: "#FF6C3C" - pressedColor: "#FF4304" - onClicked: { - console.log("saving daemon adress settings") - var newDaemon = daemonAddr.text.trim() + ":" + daemonPort.text.trim() - if(persistentSettings.daemon_address != newDaemon) { - persistentSettings.daemon_address = newDaemon + RowLayout { + visible: persistentSettings.useRemoteNode + ColumnLayout { + Label { + color: "#4A4949" + text: qsTr("Remote node") + translationManager.emptyString + } + RemoteNodeEdit { + id: remoteNodeEdit + Layout.minimumWidth: 100 * scaleRatio + daemonAddrText: persistentSettings.remoteNodeAddress.split(":")[0] + daemonPortText: (persistentSettings.remoteNodeAddress.split(":")[1] == "") ? "18081" : persistentSettings.remoteNodeAddress.split(":")[1] + onEditingFinished: { + persistentSettings.remoteNodeAddress = remoteNodeEdit.getAddress(); + console.log("setting remote node to " + persistentSettings.remoteNodeAddress) } + } + + StandardButton { + id: remoteNodeSave + text: qsTr("Connect") + translationManager.emptyString + shadowReleasedColor: "#FF4304" + shadowPressedColor: "#B32D00" + releasedColor: "#FF6C3C" + pressedColor: "#FF4304" + onClicked: { + // Update daemon login + persistentSettings.remoteNodeAddress = remoteNodeEdit.getAddress(); + persistentSettings.daemonUsername = daemonUsername.text; + persistentSettings.daemonPassword = daemonPassword.text; + persistentSettings.useRemoteNode = true - // Update daemon login - persistentSettings.daemonUsername = daemonUsername.text; - persistentSettings.daemonPassword = daemonPassword.text; - currentWallet.setDaemonLogin(persistentSettings.daemonUsername, persistentSettings.daemonPassword); + currentWallet.setDaemonLogin(persistentSettings.daemonUsername, persistentSettings.daemonPassword); - //Reinit wallet - currentWallet.initAsync(newDaemon); + appWindow.connectRemoteNode() + } } } } RowLayout { + visible: !isMobile Label { color: "#4A4949" text: qsTr("Layout settings") + translationManager.emptyString - fontSize: 16 - anchors.topMargin: 30 - Layout.topMargin: 30 + anchors.topMargin: 30 * scaleRatio + Layout.topMargin: 30 * scaleRatio } } Rectangle { + visible: !isMobile Layout.fillWidth: true height: 1 color: "#DEDEDE" @@ -393,6 +406,7 @@ Rectangle { RowLayout { CheckBox { + visible: !isMobile id: customDecorationsCheckBox checked: persistentSettings.customDecorations onClicked: appWindow.setCustomWindowDecorations(checked) @@ -627,7 +641,7 @@ Rectangle { function onPageCompleted() { console.log("Settings page loaded"); initSettings(); - viewOnly = currentWallet.viewOnly; + if(typeof daemonManager != "undefined") appWindow.daemonRunning = daemonManager.running(persistentSettings.testnet)