diff --git a/main.qml b/main.qml
index 679195746f..d67f321406 100644
--- a/main.qml
+++ b/main.qml
@@ -787,7 +787,13 @@ ApplicationWindow {
const noSync = appWindow.walletMode === 0;
const bootstrapNodeAddress = persistentSettings.walletMode < 2 ? "auto" : persistentSettings.bootstrapNodeAddress
- daemonManager.start(flags, persistentSettings.nettype, persistentSettings.blockchainDataDir, bootstrapNodeAddress, noSync, persistentSettings.pruneBlockchain);
+
+ var allFlags = flags;
+ if (persistentSettings.anonymityNetworkType === 1) {
+ allFlags = (allFlags + " --i2p-sam " + persistentSettings.i2pRouterAddress + ":" + persistentSettings.i2pSamPort).trim();
+ }
+
+ daemonManager.start(allFlags, persistentSettings.nettype, persistentSettings.blockchainDataDir, bootstrapNodeAddress, noSync, persistentSettings.pruneBlockchain);
}
function stopDaemon(callback, splash){
@@ -1514,6 +1520,10 @@ ApplicationWindow {
property int autosaveMinutes: 10
property bool pruneBlockchain: false
+ property int anonymityNetworkType: 0
+ property string i2pRouterAddress: "127.0.0.1"
+ property string i2pSamPort: "7656"
+
property bool fiatPriceEnabled: false
property bool fiatPriceToggle: false
property string fiatPriceProvider: "kraken"
diff --git a/pages/settings/SettingsNode.qml b/pages/settings/SettingsNode.qml
index 28480419ff..5e90c55ef6 100644
--- a/pages/settings/SettingsNode.qml
+++ b/pages/settings/SettingsNode.qml
@@ -352,6 +352,116 @@ Rectangle{
}
}
}
+
+ Timer {
+ id: i2pStatusTimer
+ interval: 5000
+ running: appWindow.persistentSettings.anonymityNetworkType === 1
+ repeat: true
+ triggeredOnStart: true
+ onTriggered: {
+ var host = appWindow.persistentSettings.i2pRouterAddress || "127.0.0.1";
+ var port = parseInt(appWindow.persistentSettings.i2pSamPort) || 7656;
+ walletManager.checkI2PSamAsync(host, port, function(reachable) {
+ var color = reachable ? (MoneroComponents.Style.blackTheme ? "lime" : "green") : MoneroComponents.Style.errorColor;
+ var label = reachable ? qsTr("Router is online") : qsTr("Router is offline");
+ i2pStatus.text = "" + label + "";
+ });
+ }
+ }
+
+ MoneroComponents.Label {
+ id: soloTitleLabel
+ fontSize: 18
+ text: qsTr("Anonymity network") + translationManager.emptyString
+ }
+
+ ColumnLayout {
+ spacing: 20
+ Layout.fillWidth: true
+ id: networkColumn
+ z: parent.z + 1
+
+ MoneroComponents.StandardDropdown {
+ id: anonymityNetworkDropdown
+ Layout.maximumWidth: 200
+ dataModel: anonymityNetworkModel
+ currentIndex: appWindow.persistentSettings.anonymityNetworkType
+ onChanged: {
+ appWindow.persistentSettings.anonymityNetworkType = currentIndex;
+ }
+ }
+
+ ColumnLayout {
+ id: i2pSettings
+ spacing: 20
+ Layout.fillWidth: true
+ visible: appWindow.persistentSettings.anonymityNetworkType === 1
+
+ MoneroComponents.TextPlain {
+ id: soloMainLabel
+ text: qsTr("Configure your I2P connection settings. Most users should stick to the default settings.") + translationManager.emptyString
+ wrapMode: Text.Wrap
+ Layout.fillWidth: true
+ font.family: MoneroComponents.Style.fontRegular.name
+ font.pixelSize: 14
+ color: MoneroComponents.Style.defaultFontColor
+ }
+
+ RowLayout {
+ spacing: 32
+ Layout.fillWidth: true
+
+ MoneroComponents.LineEdit {
+ id: i2pRouterAddress
+ Layout.fillWidth: true
+ Layout.preferredWidth: 300
+ labelFontSize: 14
+ labelText: qsTr("Router address") + translationManager.emptyString
+ text: appWindow.persistentSettings.i2pRouterAddress || "127.0.0.1"
+ placeholderText: "127.0.0.1"
+ placeholderFontSize: 14
+ fontSize: 14
+ onEditingFinished: {
+ appWindow.persistentSettings.i2pRouterAddress = text
+ }
+ }
+
+ MoneroComponents.LineEdit {
+ id: i2pSamPort
+ Layout.fillWidth: true
+ Layout.preferredWidth: 100
+ labelFontSize: 14
+ labelText: qsTr("SAM port") + translationManager.emptyString
+ text: appWindow.persistentSettings.i2pSamPort || "7656"
+ placeholderText: "7656"
+ placeholderFontSize: 14
+ fontSize: 14
+ onEditingFinished: {
+ appWindow.persistentSettings.i2pSamPort = text
+ }
+ }
+ }
+
+ Text {
+ id: i2pStatus
+ textFormat: Text.RichText
+ font.family: MoneroComponents.Style.fontRegular.name
+ font.pixelSize: 14
+ text: "" + qsTr("Checking router status...") + ""
+ }
+ }
+ }
+
+ ListModel {
+ id: anonymityNetworkModel
+ ListElement {
+ column1: "None"
+ }
+ ListElement {
+ column1: "I2P"
+ }
+ }
}
}
}
diff --git a/src/libwalletqt/WalletManager.cpp b/src/libwalletqt/WalletManager.cpp
index ae03357b5e..eaf590a207 100644
--- a/src/libwalletqt/WalletManager.cpp
+++ b/src/libwalletqt/WalletManager.cpp
@@ -42,6 +42,7 @@
#include
#include
#include
+#include "net/net_helper.h"
#include "qt/updater.h"
#include "qt/ScopeGuard.h"
@@ -378,6 +379,19 @@ bool WalletManager::stopMining()
return m_pimpl->stopMining();
}
+void WalletManager::checkI2PSamAsync(const QString &host, int port, const QJSValue &callback)
+{
+ m_scheduler.run([host, port] {
+ epee::net_utils::blocked_mode_client client;
+ client.set_ssl(epee::net_utils::ssl_support_t::e_ssl_support_disabled);
+ const bool reachable = client.connect(
+ host.toStdString(),
+ std::to_string(port),
+ std::chrono::milliseconds{2000});
+ return QJSValueList{reachable};
+ }, callback);
+}
+
bool WalletManager::localDaemonSynced() const
{
return blockchainHeight() > 1 && blockchainHeight() >= blockchainTargetHeight();
diff --git a/src/libwalletqt/WalletManager.h b/src/libwalletqt/WalletManager.h
index e98648c120..6dd384f9ce 100644
--- a/src/libwalletqt/WalletManager.h
+++ b/src/libwalletqt/WalletManager.h
@@ -162,6 +162,8 @@ class WalletManager : public QObject, public PassprasePrompter
Q_INVOKABLE bool startMining(const QString &address, quint32 threads, bool backgroundMining, bool ignoreBattery);
Q_INVOKABLE bool stopMining();
+ Q_INVOKABLE void checkI2PSamAsync(const QString &host, int port, const QJSValue &callback);
+
// QML missing such functionality, implementing these helpers here
Q_INVOKABLE QString urlToLocalPath(const QUrl &url) const;
Q_INVOKABLE QUrl localPathToUrl(const QString &path) const;