Merge pull request #3373

6bc9627 SettingsNode: implement multiple remote nodes support (xiphon)
This commit is contained in:
luigi1111 2021-04-06 11:35:23 -05:00
commit 183585653f
No known key found for this signature in database
GPG Key ID: F4ACA0183641E010
7 changed files with 435 additions and 89 deletions

66
components/Dialog.qml Normal file
View File

@ -0,0 +1,66 @@
// Copyright (c) 2021, 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.9
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.1
import "." as MoneroComponents
Popup {
id: dialog
default property alias content: mainLayout.children
property alias title: header.text
background: Rectangle {
border.color: MoneroComponents.Style.blackTheme ? Qt.rgba(255, 255, 255, 0.25) : Qt.rgba(0, 0, 0, 0.25)
border.width: 1
color: MoneroComponents.Style.blackTheme ? "black" : "white"
radius: 10
}
closePolicy: Popup.CloseOnEscape
focus: true
padding: 20
x: (appWindow.width - width) / 2
y: (appWindow.height - height) / 2
ColumnLayout {
id: mainLayout
spacing: dialog.padding
Text {
id: header
color: MoneroComponents.Style.defaultFontColor
font.bold: true
font.family: MoneroComponents.Style.fontRegular.name
font.pixelSize: 18
visible: text != ""
}
}
}

View File

@ -0,0 +1,153 @@
// Copyright (c) 2021, 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.9
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.1
import "." as MoneroComponents
MoneroComponents.Dialog {
id: root
title: (editMode ? qsTr("Edit remote node") : qsTr("Add remote node")) + translationManager.emptyString
property var callbackOnSuccess: null
property bool editMode: false
property bool success: false
onActiveFocusChanged: activeFocus && remoteNodeAddress.forceActiveFocus()
function add(callbackOnSuccess) {
root.editMode = false;
root.callbackOnSuccess = callbackOnSuccess;
open();
}
function edit(remoteNode, callbackOnSuccess) {
const hostPort = remoteNode.address.match(/^(.*?)(?:\:?(\d*))$/);
if (hostPort) {
remoteNodeAddress.daemonAddrText = hostPort[1];
remoteNodeAddress.daemonPortText = hostPort[2];
}
daemonUsername.text = remoteNode.username;
daemonPassword.text = remoteNode.password;
setTrustedDaemonCheckBox.checked = remoteNode.trusted;
root.callbackOnSuccess = callbackOnSuccess;
root.editMode = true;
open();
}
onClosed: {
if (root.success && callbackOnSuccess) {
callbackOnSuccess({
address: remoteNodeAddress.getAddress(),
username: daemonUsername.text,
password: daemonPassword.text,
trusted: setTrustedDaemonCheckBox.checked,
});
}
remoteNodeAddress.daemonAddrText = "";
remoteNodeAddress.daemonPortText = "";
daemonUsername.text = "";
daemonPassword.text = "";
setTrustedDaemonCheckBox.checked = false;
root.success = false;
}
MoneroComponents.RemoteNodeEdit {
id: remoteNodeAddress
Layout.fillWidth: true
placeholderFontSize: 15
daemonAddrLabelText: qsTr("Address") + translationManager.emptyString
daemonPortLabelText: qsTr("Port") + translationManager.emptyString
}
RowLayout {
Layout.fillWidth: true
spacing: 32
MoneroComponents.LineEdit {
id: daemonUsername
Layout.fillWidth: true
Layout.minimumWidth: 220
labelText: qsTr("Daemon username") + translationManager.emptyString
placeholderText: qsTr("(optional)") + translationManager.emptyString
placeholderFontSize: 15
labelFontSize: 14
fontSize: 15
}
MoneroComponents.LineEdit {
id: daemonPassword
Layout.fillWidth: true
Layout.minimumWidth: 220
labelText: qsTr("Daemon password") + translationManager.emptyString
placeholderText: qsTr("Password") + translationManager.emptyString
password: true
placeholderFontSize: 15
labelFontSize: 14
fontSize: 15
}
}
MoneroComponents.CheckBox {
id: setTrustedDaemonCheckBox
activeFocusOnTab: true
text: qsTr("Mark as Trusted Daemon") + translationManager.emptyString
}
RowLayout {
Layout.alignment: Qt.AlignRight
spacing: parent.spacing
MoneroComponents.StandardButton {
activeFocusOnTab: true
fontBold: false
primary: false
text: qsTr("Cancel") + translationManager.emptyString
onClicked: root.close()
}
MoneroComponents.StandardButton {
activeFocusOnTab: true
fontBold: false
enabled: remoteNodeAddress.getAddress() != ""
text: qsTr("Ok") + translationManager.emptyString
onClicked: {
root.success = true;
root.close();
}
}
}
}

134
main.qml
View File

@ -26,6 +26,7 @@
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF // 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. // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import QtQml.Models 2.12
import QtQuick 2.9 import QtQuick 2.9
import QtQuick.Window 2.0 import QtQuick.Window 2.0
import QtQuick.Controls 1.1 import QtQuick.Controls 1.1
@ -364,13 +365,13 @@ ApplicationWindow {
console.log("Recovering from seed: ", persistentSettings.is_recovering) console.log("Recovering from seed: ", persistentSettings.is_recovering)
console.log("restore Height", persistentSettings.restore_height) console.log("restore Height", persistentSettings.restore_height)
// Use saved daemon rpc login settings if (persistentSettings.useRemoteNode) {
currentWallet.setDaemonLogin(persistentSettings.daemonUsername, persistentSettings.daemonPassword) const remoteNode = remoteNodesModel.currentRemoteNode();
currentDaemonAddress = remoteNode.address;
if(persistentSettings.useRemoteNode) currentWallet.setDaemonLogin(remoteNode.username, remoteNode.password);
currentDaemonAddress = persistentSettings.remoteNodeAddress } else {
else currentDaemonAddress = localDaemonAddress;
currentDaemonAddress = localDaemonAddress }
console.log("initializing with daemon address: ", currentDaemonAddress) console.log("initializing with daemon address: ", currentDaemonAddress)
currentWallet.initAsync( currentWallet.initAsync(
@ -387,7 +388,7 @@ ApplicationWindow {
} }
function isTrustedDaemon() { function isTrustedDaemon() {
return !persistentSettings.useRemoteNode || persistentSettings.is_trusted_daemon; return !persistentSettings.useRemoteNode || remoteNodesModel.currentRemoteNode().trusted;
} }
function usefulName(path) { function usefulName(path) {
@ -616,7 +617,9 @@ ApplicationWindow {
const callback = function() { const callback = function() {
persistentSettings.useRemoteNode = true; persistentSettings.useRemoteNode = true;
currentDaemonAddress = persistentSettings.remoteNodeAddress; const remoteNode = remoteNodesModel.currentRemoteNode();
currentDaemonAddress = remoteNode.address;
currentWallet.setDaemonLogin(remoteNode.username, remoteNode.password);
currentWallet.initAsync( currentWallet.initAsync(
currentDaemonAddress, currentDaemonAddress,
isTrustedDaemon(), isTrustedDaemon(),
@ -642,6 +645,7 @@ ApplicationWindow {
console.log("disconnecting remote node"); console.log("disconnecting remote node");
persistentSettings.useRemoteNode = false; persistentSettings.useRemoteNode = false;
currentDaemonAddress = localDaemonAddress currentDaemonAddress = localDaemonAddress
currentWallet.setDaemonLogin("", "");
currentWallet.initAsync( currentWallet.initAsync(
currentDaemonAddress, currentDaemonAddress,
isTrustedDaemon(), isTrustedDaemon(),
@ -1350,6 +1354,8 @@ ApplicationWindow {
confirmationDialog.open(); confirmationDialog.open();
} }
} }
remoteNodesModel.initialize();
} }
MoneroSettings { MoneroSettings {
@ -1370,22 +1376,33 @@ ApplicationWindow {
property bool miningIgnoreBattery : true property bool miningIgnoreBattery : true
property var nettype: NetworkType.MAINNET property var nettype: NetworkType.MAINNET
property int restore_height : 0 property int restore_height : 0
property bool is_trusted_daemon : false property bool is_trusted_daemon : false // TODO: drop after v0.17.2.0 release
property bool is_recovering : false property bool is_recovering : false
property bool is_recovering_from_device : false property bool is_recovering_from_device : false
property bool customDecorations : true property bool customDecorations : true
property string daemonFlags property string daemonFlags
property int logLevel: 0 property int logLevel: 0
property string logCategories: "" property string logCategories: ""
property string daemonUsername: "" property string daemonUsername: "" // TODO: drop after v0.17.2.0 release
property string daemonPassword: "" property string daemonPassword: "" // TODO: drop after v0.17.2.0 release
property bool transferShowAdvanced: false property bool transferShowAdvanced: false
property bool receiveShowAdvanced: false property bool receiveShowAdvanced: false
property bool historyShowAdvanced: false property bool historyShowAdvanced: false
property bool historyHumanDates: true property bool historyHumanDates: true
property string blockchainDataDir: "" property string blockchainDataDir: ""
property bool useRemoteNode: false property bool useRemoteNode: false
property string remoteNodeAddress: "" property string remoteNodeAddress: "" // TODO: drop after v0.17.2.0 release
property string remoteNodesSerialized: JSON.stringify({
selected: 0,
nodes: remoteNodeAddress != ""
? [{
address: remoteNodeAddress,
username: daemonUsername,
password: daemonPassword,
trusted: is_trusted_daemon,
}]
: [],
})
property string bootstrapNodeAddress: "" property string bootstrapNodeAddress: ""
property bool segregatePreForkOutputs: true property bool segregatePreForkOutputs: true
property bool keyReuseMitigation2: true property bool keyReuseMitigation2: true
@ -1432,6 +1449,88 @@ ApplicationWindow {
} }
} }
ListModel {
id: remoteNodesModel
property int selected: 0
signal store()
function initialize() {
try {
const remoteNodes = JSON.parse(persistentSettings.remoteNodesSerialized);
for (var index = 0; index < remoteNodes.nodes.length; ++index) {
const remoteNode = remoteNodes.nodes[index];
remoteNodesModel.append(remoteNode);
}
selected = remoteNodes.selected % remoteNodesModel.count || 0;
} catch (e) {
console.error('failed to parse remoteNodesSerialized', e);
}
store.connect(function() {
var remoteNodes = [];
for (var index = 0; index < remoteNodesModel.count; ++index) {
remoteNodes.push(remoteNodesModel.get(index));
}
persistentSettings.remoteNodesSerialized = JSON.stringify({
selected: selected,
nodes: remoteNodes
});
});
}
function appendIfNotExists(newRemoteNode) {
for (var index = 0; index < remoteNodesModel.count; ++index) {
const remoteNode = remoteNodesModel.get(index);
if (remoteNode.address == newRemoteNode.address &&
remoteNode.username == newRemoteNode.username &&
remoteNode.password == newRemoteNode.password &&
remoteNode.trusted == newRemoteNode.trusted) {
return index;
}
}
remoteNodesModel.append(newRemoteNode);
return remoteNodesModel.count - 1;
}
function applyRemoteNode(index) {
selected = index;
const remoteNode = currentRemoteNode();
persistentSettings.useRemoteNode = true;
if (currentWallet) {
currentWallet.setDaemonLogin(remoteNode.username, remoteNode.password);
currentWallet.setTrustedDaemon(remoteNode.trusted);
appWindow.connectRemoteNode();
}
}
function currentRemoteNode() {
if (selected < remoteNodesModel.count) {
return remoteNodesModel.get(selected);
}
return {
address: "",
username: "",
password: "",
trusted: false,
};
}
function removeSelectNextIfNeeded(index) {
remoteNodesModel.remove(index);
if (selected == index) {
applyRemoteNode(selected % remoteNodesModel.count || 0);
} else if (selected > index) {
selected = selected - 1;
}
}
onCountChanged: store()
onDataChanged: store()
onSelectedChanged: store()
}
// Information dialog // Information dialog
StandardDialog { StandardDialog {
// dynamically change onclose handler // dynamically change onclose handler
@ -1512,6 +1611,10 @@ ApplicationWindow {
y: (parent.height - height) / 2 y: (parent.height - height) / 2
} }
MoneroComponents.RemoteNodeDialog {
id: remoteNodeDialog
}
// Choose blockchain folder // Choose blockchain folder
FileDialog { FileDialog {
id: blockchainFileDialog id: blockchainFileDialog
@ -1739,7 +1842,9 @@ ApplicationWindow {
anchors.fill: blurredArea anchors.fill: blurredArea
source: blurredArea source: blurredArea
radius: 64 radius: 64
visible: passwordDialog.visible || inputDialog.visible || splash.visible || updateDialog.visible || devicePassphraseDialog.visible || txConfirmationPopup.visible || successfulTxPopup.visible visible: passwordDialog.visible || inputDialog.visible || splash.visible || updateDialog.visible ||
devicePassphraseDialog.visible || txConfirmationPopup.visible || successfulTxPopup.visible ||
remoteNodeDialog.visible
} }
@ -2129,6 +2234,7 @@ ApplicationWindow {
passwordDialog.onRejectedCallback = function() { appWindow.showWizard(); } passwordDialog.onRejectedCallback = function() { appWindow.showWizard(); }
if (inputDialogVisible) inputDialog.close() if (inputDialogVisible) inputDialog.close()
remoteNodeDialog.close();
passwordDialog.open(); passwordDialog.open();
} }

View File

@ -130,7 +130,7 @@ Rectangle{
topPadding: 0 topPadding: 0
text: qsTr("The blockchain is downloaded to your computer. Provides higher security and requires more local storage.") + translationManager.emptyString text: qsTr("The blockchain is downloaded to your computer. Provides higher security and requires more local storage.") + translationManager.emptyString
width: parent.width - (localNodeIcon.width + localNodeIcon.anchors.leftMargin + anchors.leftMargin) width: parent.width - (localNodeIcon.width + localNodeIcon.anchors.leftMargin + anchors.leftMargin)
} }
} }
MouseArea { MouseArea {
@ -262,80 +262,93 @@ Rectangle{
text: qsTr("To find a remote node, type 'Monero remote node' into your favorite search engine. Please ensure the node is run by a trusted third-party.") + translationManager.emptyString text: qsTr("To find a remote node, type 'Monero remote node' into your favorite search engine. Please ensure the node is run by a trusted third-party.") + translationManager.emptyString
} }
MoneroComponents.RemoteNodeEdit {
id: remoteNodeEdit
Layout.minimumWidth: 100
placeholderFontSize: 15
daemonAddrLabelText: qsTr("Address") + translationManager.emptyString
daemonPortLabelText: qsTr("Port") + translationManager.emptyString
initialAddress: persistentSettings.remoteNodeAddress
onEditingFinished: {
persistentSettings.remoteNodeAddress = remoteNodeEdit.getAddress();
console.log("setting remote node to " + persistentSettings.remoteNodeAddress);
if (persistentSettings.is_trusted_daemon) {
persistentSettings.is_trusted_daemon = !persistentSettings.is_trusted_daemon
currentWallet.setTrustedDaemon(persistentSettings.is_trusted_daemon)
setTrustedDaemonCheckBox.checked = !setTrustedDaemonCheckBox.checked
appWindow.showStatusMessage(qsTr("Remote node updated. Trusted daemon has been reset. Mark again, if desired."), 8);
}
}
}
GridLayout {
columns: 2
columnSpacing: 32
MoneroComponents.LineEdit {
id: daemonUsername
Layout.fillWidth: true
labelText: qsTr("Daemon username") + translationManager.emptyString
text: persistentSettings.daemonUsername
placeholderText: qsTr("(optional)") + translationManager.emptyString
placeholderFontSize: 15
labelFontSize: 14
fontSize: 15
}
MoneroComponents.LineEdit {
id: daemonPassword
Layout.fillWidth: true
labelText: qsTr("Daemon password") + translationManager.emptyString
text: persistentSettings.daemonPassword
placeholderText: qsTr("Password") + translationManager.emptyString
password: true
placeholderFontSize: 15
labelFontSize: 14
fontSize: 15
}
}
MoneroComponents.CheckBox { MoneroComponents.CheckBox {
id: setTrustedDaemonCheckBox border: false
checked: persistentSettings.is_trusted_daemon checkedIcon: FontAwesome.minusCircle
onClicked: { uncheckedIcon: FontAwesome.plusCircle
persistentSettings.is_trusted_daemon = !persistentSettings.is_trusted_daemon fontAwesomeIcons: true
currentWallet.setTrustedDaemon(persistentSettings.is_trusted_daemon) fontSize: 16
} iconOnTheLeft: true
text: qsTr("Mark as Trusted Daemon") + translationManager.emptyString text: qsTr("Add remote node") + translationManager.emptyString
toggleOnClick: false
onClicked: remoteNodeDialog.add(remoteNodesModel.append)
} }
MoneroComponents.StandardButton { ColumnLayout {
id: btnConnectRemote spacing: 0
enabled: remoteNodeEdit.isValid()
small: true
text: qsTr("Connect") + translationManager.emptyString
onClicked: {
// Update daemon login
persistentSettings.remoteNodeAddress = remoteNodeEdit.getAddress();
persistentSettings.daemonUsername = daemonUsername.text;
persistentSettings.daemonPassword = daemonPassword.text;
persistentSettings.useRemoteNode = true
currentWallet.setDaemonLogin(persistentSettings.daemonUsername, persistentSettings.daemonPassword); Repeater {
model: remoteNodesModel
appWindow.connectRemoteNode() Rectangle {
height: 30
Layout.fillWidth: true
color: itemMouseArea.containsMouse || index === remoteNodesModel.selected ? MoneroComponents.Style.titleBarButtonHoverColor : "transparent"
Rectangle {
color: MoneroComponents.Style.appWindowBorderColor
anchors.right: parent.right
anchors.left: parent.left
anchors.top: parent.top
height: 1
visible: index > 0
MoneroEffects.ColorTransition {
targetObj: parent
blackColor: MoneroComponents.Style._b_appWindowBorderColor
whiteColor: MoneroComponents.Style._w_appWindowBorderColor
}
}
Rectangle {
anchors.fill: parent
anchors.rightMargin: 80
color: "transparent"
MoneroComponents.TextPlain {
color: index === remoteNodesModel.selected ? MoneroComponents.Style.defaultFontColor : MoneroComponents.Style.dimmedFontColor
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: 6
font.pixelSize: 16
text: address
themeTransition: false
}
MouseArea {
id: itemMouseArea
cursorShape: Qt.PointingHandCursor
anchors.fill: parent
hoverEnabled: true
onClicked: remoteNodesModel.applyRemoteNode(index)
}
}
RowLayout {
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: 6
height: 30
spacing: 10
MoneroComponents.InlineButton {
buttonColor: "transparent"
fontFamily: FontAwesome.fontFamily
text: FontAwesome.edit
onClicked: remoteNodeDialog.edit(remoteNodesModel.get(index), function (remoteNode) {
remoteNodesModel.set(index, remoteNode)
})
}
MoneroComponents.InlineButton {
buttonColor: "transparent"
fontFamily: FontAwesome.fontFamily
text: FontAwesome.times
visible: remoteNodesModel.count > 1
onClicked: remoteNodesModel.removeSelectNextIfNeeded(index)
}
}
}
} }
} }
} }
@ -431,7 +444,7 @@ Rectangle{
} }
} }
} }
} }
} }
} }

View File

@ -3,10 +3,12 @@
<file>main.qml</file> <file>main.qml</file>
<file>LeftPanel.qml</file> <file>LeftPanel.qml</file>
<file>MiddlePanel.qml</file> <file>MiddlePanel.qml</file>
<file>components/Dialog.qml</file>
<file>components/Label.qml</file> <file>components/Label.qml</file>
<file>components/LanguageButton.qml</file> <file>components/LanguageButton.qml</file>
<file>components/Navbar.qml</file> <file>components/Navbar.qml</file>
<file>components/NavbarItem.qml</file> <file>components/NavbarItem.qml</file>
<file>components/RemoteNodeDialog.qml</file>
<file>components/SettingsListItem.qml</file> <file>components/SettingsListItem.qml</file>
<file>components/Slider.qml</file> <file>components/Slider.qml</file>
<file>components/UpdateDialog.qml</file> <file>components/UpdateDialog.qml</file>

View File

@ -42,7 +42,13 @@ ColumnLayout {
function save(){ function save(){
persistentSettings.useRemoteNode = remoteNode.checked persistentSettings.useRemoteNode = remoteNode.checked
persistentSettings.remoteNodeAddress = remoteNodeEdit.getAddress(); const index = remoteNodesModel.appendIfNotExists({
address: remoteNodeEdit.getAddress(),
username: "",
password: "",
trusted: false,
});
remoteNodesModel.applyRemoteNode(index);
if (bootstrapNodeEdit.daemonAddrText == "auto") { if (bootstrapNodeEdit.daemonAddrText == "auto") {
persistentSettings.bootstrapNodeAddress = "auto"; persistentSettings.bootstrapNodeAddress = "auto";
} else { } else {
@ -201,7 +207,7 @@ ColumnLayout {
id: remoteNodeEdit id: remoteNodeEdit
Layout.fillWidth: true Layout.fillWidth: true
initialAddress: persistentSettings.remoteNodeAddress initialAddress: remoteNodesModel.currentRemoteNode().address
} }
} }
} }

View File

@ -65,10 +65,10 @@ ColumnLayout {
} }
WizardSummaryItem { WizardSummaryItem {
visible: persistentSettings.remoteNodeAddress !== "" && appWindow.walletMode == 0 visible: remoteNodesModel.currentRemoteNode().address !== "" && appWindow.walletMode == 0
Layout.fillWidth: true Layout.fillWidth: true
header: qsTr("Daemon address") + translationManager.emptyString header: qsTr("Daemon address") + translationManager.emptyString
value: persistentSettings.remoteNodeAddress value: remoteNodesModel.currentRemoteNode().address
} }
WizardSummaryItem { WizardSummaryItem {