diff --git a/LeftPanel.qml b/LeftPanel.qml
index 65dbadad..a5766c3e 100644
--- a/LeftPanel.qml
+++ b/LeftPanel.qml
@@ -337,29 +337,6 @@ Rectangle {
height: 1
}
- /* // ------------- Mining tab ---------------
- MenuButton {
- id: miningButton
- anchors.left: parent.left
- anchors.right: parent.right
- text: qsTr("Mining") + translationManager.emptyString
- symbol: qsTr("M") + translationManager.emptyString
- dotColor: "#FFD781"
- onClicked: {
- parent.previousButton.checked = false
- parent.previousButton = miningButton
- panel.miningClicked()
- }
- }
-
- Rectangle {
- anchors.left: parent.left
- anchors.right: parent.right
- anchors.leftMargin: 16
- color: miningButton.checked || settingsButton.checked ? "#1C1C1C" : "#505050"
- height: 1
- }
- */
// ------------- Advanced tab ---------------
MenuButton {
id: advancedButton
@@ -381,6 +358,29 @@ Rectangle {
height: 1
}
+ // ------------- Mining tab ---------------
+ MenuButton {
+ id: miningButton
+ anchors.left: parent.left
+ anchors.right: parent.right
+ text: qsTr("Mining") + translationManager.emptyString
+ symbol: qsTr("M") + translationManager.emptyString
+ dotColor: "#FFD781"
+ under: advancedButton
+ onClicked: {
+ parent.previousButton.checked = false
+ parent.previousButton = miningButton
+ panel.miningClicked()
+ }
+ }
+
+ Rectangle {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.leftMargin: 16
+ color: miningButton.checked || settingsButton.checked ? "#1C1C1C" : "#505050"
+ height: 1
+ }
// ------------- TxKey tab ---------------
MenuButton {
id: txkeyButton
diff --git a/MiddlePanel.qml b/MiddlePanel.qml
index 94ecc17e..6c18a56e 100644
--- a/MiddlePanel.qml
+++ b/MiddlePanel.qml
@@ -52,6 +52,7 @@ Rectangle {
property History historyView: History { }
property Sign signView: Sign { }
property Settings settingsView: Settings { }
+ property Mining miningView: Mining { }
property AddressBook addressBookView: AddressBook { }
@@ -144,7 +145,7 @@ Rectangle {
PropertyChanges { target: root; currentView: settingsView }
}, State {
name: "Mining"
- PropertyChanges { /*TODO*/ }
+ PropertyChanges { target: root; currentView: miningView }
}
]
diff --git a/components/StandardDropdown.qml b/components/StandardDropdown.qml
index f5c81796..b3820501 100644
--- a/components/StandardDropdown.qml
+++ b/components/StandardDropdown.qml
@@ -107,7 +107,7 @@ Item {
font.bold: true
font.pixelSize: 12
color: "#FFFFFF"
- text: repeater.model.get(column.currentIndex).column1
+ text: column.currentIndex < repeater.model.rowCount() ? repeater.model.get(column.currentIndex).column1 : ""
}
Text {
@@ -119,7 +119,7 @@ Item {
font.family: "Arial"
font.pixelSize: 12
color: "#FFFFFF"
- text: repeater.model.get(column.currentIndex).column2
+ text: column.currentIndex < repeater.model.rowCount() ? repeater.model.get(column.currentIndex).column2 : ""
property int w: 0
Component.onCompleted: w = implicitWidth
diff --git a/main.qml b/main.qml
index 3144a70e..663f9005 100644
--- a/main.qml
+++ b/main.qml
@@ -379,7 +379,6 @@ ApplicationWindow {
daemonRunning = false;
}
-
function onWalletNewBlock(blockHeight) {
// Update progress bar
var currHeight = blockHeight
@@ -867,7 +866,7 @@ ApplicationWindow {
onTxkeyClicked: middlePanel.state = "TxKey"
onHistoryClicked: middlePanel.state = "History"
onAddressBookClicked: middlePanel.state = "AddressBook"
- onMiningClicked: middlePanel.state = "Minning"
+ onMiningClicked: middlePanel.state = "Mining"
onSignClicked: middlePanel.state = "Sign"
onSettingsClicked: middlePanel.state = "Settings"
}
@@ -1149,7 +1148,7 @@ ApplicationWindow {
onClosing: {
// Close wallet non async on exit
walletManager.closeWallet();
- // Stop daemon
+ // Stop daemon and pool miner
daemonManager.stop();
}
}
diff --git a/pages/Mining.qml b/pages/Mining.qml
index e9a50476..602ded59 100644
--- a/pages/Mining.qml
+++ b/pages/Mining.qml
@@ -27,8 +27,193 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import QtQuick 2.0
+import QtQuick.Layouts 1.1
+import QtQuick.Dialogs 1.2
+import "../components"
+import moneroComponents.Wallet 1.0
Rectangle {
- width: 100
- height: 62
+ id: root
+ color: "#F0EEEE"
+ property var currentHashRate: 0
+
+ function isDaemonLocal() {
+ var daemonAddress = appWindow.persistentSettings.daemon_address
+ if (daemonAddress === "")
+ return false
+ var daemonHost = daemonAddress.split(":")[0]
+ if (daemonHost === "127.0.0.1" || daemonHost === "localhost")
+ return true
+ return false
+ }
+
+ /* main layout */
+ ColumnLayout {
+ id: mainLayout
+ anchors.margins: 10
+ anchors.left: parent.left
+ anchors.top: parent.top
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ spacing: 20
+
+ Rectangle {
+ anchors.fill: soloBox
+ color: "#00000000"
+ border.width: 2
+ border.color: "#CCCCCC"
+ anchors.margins: -15
+ }
+
+ // solo
+ ColumnLayout {
+ id: soloBox
+ anchors.margins: 40
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.top: parent.top
+
+ Label {
+ id: soloTitleLabel
+ fontSize: 24
+ text: qsTr("Monero solo mining")
+ }
+
+ Label {
+ id: soloLocalDaemonsLabel
+ fontSize: 18
+ color: "#D02020"
+ text: qsTr("(only available for local daemons)")
+ visible: !isDaemonLocal()
+ }
+
+ Text {
+ id: soloMainLabel
+ text: qsTr("Mining helps the Monero network build resilience.
")
+ + qsTr("The more mining is done, the harder it is to attack the network.
")
+ + qsTr("Moreover, mining gives you a small chance to earn some Monero.
")
+ + qsTr("Your computer will search for Monero block solutions.
")
+ + qsTr("If you find one, you will get the associated block reward.
")
+ + translationManager.emptyString
+ wrapMode: Text.Wrap
+ }
+
+ RowLayout {
+ id: soloMinerThreadsRow
+ Label {
+ id: soloMinerThreadsLabel
+ color: "#4A4949"
+ text: qsTr("Solo miner threads") + translationManager.emptyString
+ fontSize: 16
+ }
+ LineEdit {
+ id: soloMinerThreadsLine
+ Layout.preferredWidth: 200
+ text: "1"
+ placeholderText: qsTr("(optional)") + translationManager.emptyString
+ validator: IntValidator { bottom: 1 }
+ }
+ }
+
+ RowLayout {
+ Label {
+ id: manageSoloMinerLabel
+ color: "#4A4949"
+ text: qsTr("Manage solo miner") + translationManager.emptyString
+ fontSize: 16
+ }
+
+ StandardButton {
+ visible: true
+ //enabled: !walletManager.isMining()
+ id: startSoloMinerButton
+ width: 110
+ text: qsTr("Start mining") + translationManager.emptyString
+ shadowReleasedColor: "#FF4304"
+ shadowPressedColor: "#B32D00"
+ releasedColor: "#FF6C3C"
+ pressedColor: "#FF4304"
+ onClicked: {
+ var success = walletManager.startMining(appWindow.currentWallet.address, soloMinerThreadsLine.text)
+ if (success) {
+ update()
+ } else {
+ errorPopup.title = qsTr("Error starting mining") + translationManager.emptyString;
+ errorPopup.text = qsTr("Couldn't start mining.
")
+ if (!isDaemonLocal())
+ errorPopup.text += qsTr("Mining is only available on local daemons. Run a local daemon to be able to mine.
")
+ errorPopup.icon = StandardIcon.Critical
+ errorPopup.open()
+ }
+ }
+ }
+
+ StandardButton {
+ visible: true
+ //enabled: walletManager.isMining()
+ id: stopSoloMinerButton
+ width: 110
+ text: qsTr("Stop mining") + translationManager.emptyString
+ shadowReleasedColor: "#FF4304"
+ shadowPressedColor: "#B32D00"
+ releasedColor: "#FF6C3C"
+ pressedColor: "#FF4304"
+ onClicked: {
+ walletManager.stopMining()
+ update()
+ }
+ }
+ }
+ }
+
+ Text {
+ id: statusText
+ anchors.leftMargin: 40
+ anchors.topMargin: 17
+ text: qsTr("Status: not mining")
+ textFormat: Text.RichText
+ wrapMode: Text.Wrap
+ }
+ }
+
+ function updateStatusText() {
+ var text = ""
+ if (walletManager.isMining()) {
+ if (text !== "")
+ text += "
";
+ text += qsTr("Mining at %1 H/s").arg(walletManager.miningHashRate())
+ }
+ if (text === "") {
+ text += qsTr("Not mining") + translationManager.emptyString;
+ }
+ statusText.text = qsTr("Status: ") + text
+ }
+
+ function update() {
+ updateStatusText()
+ startSoloMinerButton.enabled = !walletManager.isMining()
+ stopSoloMinerButton.enabled = !startSoloMinerButton.enabled
+ }
+
+ StandardDialog {
+ id: errorPopup
+ cancelVisible: false
+ }
+
+ Timer {
+ id: timer
+ interval: 2000; running: false; repeat: true
+ onTriggered: update()
+ }
+
+ function onPageCompleted() {
+ console.log("Mining page loaded");
+
+ update()
+ timer.running = true
+
+ }
+ function onPageClosed() {
+ timer.running = false
+ }
}
diff --git a/src/libwalletqt/WalletManager.cpp b/src/libwalletqt/WalletManager.cpp
index 5a090ec3..fafed695 100644
--- a/src/libwalletqt/WalletManager.cpp
+++ b/src/libwalletqt/WalletManager.cpp
@@ -227,6 +227,21 @@ double WalletManager::miningHashRate() const
return m_pimpl->miningHashRate();
}
+bool WalletManager::isMining() const
+{
+ return m_pimpl->isMining();
+}
+
+bool WalletManager::startMining(const QString &address, quint32 threads)
+{
+ return m_pimpl->startMining(address.toStdString(), threads);
+}
+
+bool WalletManager::stopMining()
+{
+ return m_pimpl->stopMining();
+}
+
QString WalletManager::resolveOpenAlias(const QString &address) const
{
bool dnssec_valid = false;
diff --git a/src/libwalletqt/WalletManager.h b/src/libwalletqt/WalletManager.h
index 6673061a..5121b8dc 100644
--- a/src/libwalletqt/WalletManager.h
+++ b/src/libwalletqt/WalletManager.h
@@ -103,6 +103,10 @@ public:
Q_INVOKABLE quint64 blockchainTargetHeight() const;
Q_INVOKABLE double miningHashRate() const;
+ Q_INVOKABLE bool isMining() const;
+ Q_INVOKABLE bool startMining(const QString &address, quint32 threads);
+ Q_INVOKABLE bool stopMining();
+
// QML missing such functionality, implementing these helpers here
Q_INVOKABLE QString urlToLocalPath(const QUrl &url) const;
Q_INVOKABLE QUrl localPathToUrl(const QString &path) const;