Compare commits

..

2 Commits

Author SHA1 Message Date
luigi1111
a77a5909cf Merge pull request #2215 (again)
bf785bb build: checkout v0.14.1.0 tag (selsta)
2019-06-25 14:33:46 -05:00
selsta
bf785bb388 build: checkout v0.14.1.0 tag 2019-06-14 16:15:36 +02:00
165 changed files with 32580 additions and 33710 deletions

19
.gitignore vendored
View File

@@ -13,22 +13,3 @@ monero-wallet-gui_plugin_import.cpp
monero-wallet-gui_qml_plugin_import.cpp monero-wallet-gui_qml_plugin_import.cpp
*.qmlc *.qmlc
*.jsc *.jsc
### Vim ###
# Swap
[._]*.s[a-v][a-z]
[._]*.sw[a-p]
[._]s[a-rt-v][a-z]
[._]ss[a-gi-z]
[._]sw[a-p]
# Session
Session.vim
# Temporary
.netrwhist
*~
# Auto-generated tag files
tags
# Persistent undo
[._]*.un~

View File

@@ -40,17 +40,17 @@ import "components/effects/" as MoneroEffects
Rectangle { Rectangle {
id: panel id: panel
property int currentAccountIndex: 0 property alias unlockedBalanceText: unlockedBalanceText.text
property string currentAccountLabel: "Primary account" property alias unlockedBalanceVisible: unlockedBalanceText.visible
property string balanceString: "?.??" property alias unlockedBalanceLabelVisible: unlockedBalanceLabel.visible
property string balanceUnlockedString: "?.??" property alias balanceLabelText: balanceLabel.text
property string balanceFiatString: "?.??" property alias balanceText: balanceText.text
property string minutesToUnlock: "" property alias balanceTextFiat: balanceTextFiat.text
property bool isSyncing: false property alias unlockedBalanceTextFiat: unlockedBalanceTextFiat.text
property alias networkStatus : networkStatus property alias networkStatus : networkStatus
property alias progressBar : progressBar property alias progressBar : progressBar
property alias daemonProgressBar : daemonProgressBar property alias daemonProgressBar : daemonProgressBar
property alias minutesToUnlockTxt: unlockedBalanceLabel.text
property int titleBarHeight: 50 property int titleBarHeight: 50
property string copyValue: "" property string copyValue: ""
Clipboard { id: clipboard } Clipboard { id: clipboard }
@@ -84,7 +84,7 @@ Rectangle {
menuColumn.previousButton.checked = true menuColumn.previousButton.checked = true
} }
width: 300 width: (isMobile)? appWindow.width : 300
color: "transparent" color: "transparent"
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.top: parent.top anchors.top: parent.top
@@ -108,18 +108,19 @@ Rectangle {
visible: true visible: true
z: 2 z: 2
id: column1 id: column1
height: 175 height: 210
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: (persistentSettings.customDecorations)? 50 : 0 anchors.topMargin: (persistentSettings.customDecorations)? 50 : 0
Item { RowLayout {
Item { Item {
anchors.left: parent.left anchors.left: parent.left
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: 20 anchors.topMargin: 20
anchors.leftMargin: 20 anchors.leftMargin: 20
anchors.verticalCenter: parent.verticalCenter
height: 490 height: 490
width: 260 width: 260
@@ -127,9 +128,9 @@ Rectangle {
id: card id: card
visible: !isOpenGL || MoneroComponents.Style.blackTheme visible: !isOpenGL || MoneroComponents.Style.blackTheme
width: 260 width: 260
height: 135 height: 170
fillMode: Image.PreserveAspectFit fillMode: Image.PreserveAspectFit
source: MoneroComponents.Style.blackTheme ? "qrc:///images/card-background-black.png" : "qrc:///images/card-background-white.png" source: "qrc:///images/card-background.png"
} }
DropShadow { DropShadow {
@@ -171,6 +172,57 @@ Rectangle {
color: "#ff9323" color: "#ff9323"
themeTransition: false themeTransition: false
} }
Rectangle {
height: (logoutImage.height + 8)
width: (logoutImage.width + 8)
color: "transparent"
anchors.right: parent.right
anchors.rightMargin: 8
anchors.top: parent.top
anchors.topMargin: 25
Image {
id: logoutImage
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
height: 16
width: 13
source: "qrc:///images/logout.png"
}
MouseArea{
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
middlePanel.addressBookView.clearFields();
middlePanel.transferView.clearFields();
middlePanel.receiveView.clearFields();
appWindow.showWizard();
}
}
}
MoneroComponents.Label {
fontSize: 20
text: "¥"
color: "white"
visible: persistentSettings.fiatPriceEnabled
anchors.right: parent.right
anchors.rightMargin: 45
anchors.top: parent.top
anchors.topMargin: 28
themeTransition: false
MouseArea{
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
persistentSettings.fiatPriceToggle = !persistentSettings.fiatPriceToggle
}
}
}
} }
Item { Item {
@@ -178,155 +230,181 @@ Rectangle {
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: 20 anchors.topMargin: 20
anchors.leftMargin: 20 anchors.leftMargin: 20
anchors.verticalCenter: parent.verticalCenter
height: 490 height: 490
width: 50 width: 50
MoneroComponents.Label {
fontSize: 12
id: accountIndex
text: qsTr("Account") + " #" + currentAccountIndex
color: MoneroComponents.Style.blackTheme ? "white" : "black"
anchors.left: parent.left
anchors.leftMargin: 60
anchors.top: parent.top
anchors.topMargin: 23
themeTransition: false
MouseArea{
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: appWindow.showPageRequest("Account")
}
}
MoneroComponents.Label {
fontSize: 16
id: accountLabel
textWidth: 170
text: currentAccountLabel
color: MoneroComponents.Style.blackTheme ? "white" : "black"
anchors.left: parent.left
anchors.leftMargin: 60
anchors.top: parent.top
anchors.topMargin: 36
themeTransition: false
elide: Text.ElideRight
MouseArea {
hoverEnabled: true
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: appWindow.showPageRequest("Account")
}
}
MoneroComponents.Label {
fontSize: 16
visible: isSyncing
text: qsTr("Syncing...")
color: MoneroComponents.Style.blackTheme ? "white" : "black"
anchors.left: parent.left
anchors.leftMargin: 20
anchors.bottom: currencyLabel.top
anchors.bottomMargin: 15
themeTransition: false
}
MoneroComponents.TextPlain { MoneroComponents.TextPlain {
id: currencyLabel visible: !(persistentSettings.fiatPriceToggle && persistentSettings.fiatPriceEnabled)
font.pixelSize: 16 id: balanceText
text: { themeTransition: false
if (persistentSettings.fiatPriceEnabled && persistentSettings.fiatPriceToggle) {
return persistentSettings.fiatPriceCurrency == "xmrusd" ? "USD" : "EUR"
} else {
return "XMR"
}
}
color: MoneroComponents.Style.blackTheme ? "white" : "black"
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: 20 anchors.leftMargin: 20
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: 100 anchors.topMargin: 76
themeTransition: false font.family: "Arial"
color: "#FFFFFF"
MouseArea { text: "N/A"
hoverEnabled: true // dynamically adjust text size
anchors.fill: parent
visible: persistentSettings.fiatPriceEnabled
cursorShape: Qt.PointingHandCursor
onClicked: persistentSettings.fiatPriceToggle = !persistentSettings.fiatPriceToggle
}
}
MoneroComponents.TextPlain {
id: balancePart1
themeTransition: false
anchors.left: parent.left
anchors.leftMargin: 58
anchors.baseline: currencyLabel.baseline
color: MoneroComponents.Style.blackTheme ? "white" : "black"
text: {
if (persistentSettings.fiatPriceEnabled && persistentSettings.fiatPriceToggle) {
return balanceFiatString.split('.')[0] + "."
} else {
return balanceString.split('.')[0] + "."
}
}
font.pixelSize: { font.pixelSize: {
var defaultSize = 29; if (persistentSettings.hideBalance) {
var digits = (balancePart1.text.length - 1) return 20;
if (digits > 2 && !(persistentSettings.fiatPriceEnabled && persistentSettings.fiatPriceToggle)) {
return defaultSize - 1.1 * digits
} else {
return defaultSize
} }
var digits = text.split('.')[0].length
var defaultSize = 22;
if(digits > 2) {
return defaultSize - 1.1*digits
}
return defaultSize;
} }
MouseArea { MouseArea {
id: balancePart1MouseArea
hoverEnabled: true hoverEnabled: true
anchors.fill: parent anchors.fill: parent
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onEntered: { onEntered: {
balancePart1.color = MoneroComponents.Style.orange parent.color = MoneroComponents.Style.orange
balancePart2.color = MoneroComponents.Style.orange
} }
onExited: { onExited: {
balancePart1.color = Qt.binding(function() { return MoneroComponents.Style.blackTheme ? "white" : "black" }) parent.color = MoneroComponents.Style.white
balancePart2.color = Qt.binding(function() { return MoneroComponents.Style.blackTheme ? "white" : "black" })
} }
onClicked: { onClicked: {
console.log("Copied to clipboard"); console.log("Copied to clipboard");
clipboard.setText(balancePart1.text + balancePart2.text); clipboard.setText(parent.text);
appWindow.showStatusMessage(qsTr("Copied to clipboard"),3) appWindow.showStatusMessage(qsTr("Copied to clipboard"),3)
} }
} }
} }
MoneroComponents.TextPlain { MoneroComponents.TextPlain {
id: balancePart2 visible: !balanceText.visible
id: balanceTextFiat
themeTransition: false themeTransition: false
anchors.left: balancePart1.right anchors.left: parent.left
anchors.leftMargin: 2 anchors.leftMargin: 20
anchors.baseline: currencyLabel.baseline anchors.top: parent.top
color: MoneroComponents.Style.blackTheme ? "white" : "black" anchors.topMargin: 76
text: { font.family: "Arial"
if (persistentSettings.fiatPriceEnabled && persistentSettings.fiatPriceToggle) { color: "#FFFFFF"
return balanceFiatString.split('.')[1] text: "N/A"
} else { font.pixelSize: balanceText.font.pixelSize
return balanceString.split('.')[1]
}
}
font.pixelSize: 16
MouseArea { MouseArea {
hoverEnabled: true hoverEnabled: true
anchors.fill: parent anchors.fill: parent
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onEntered: balancePart1MouseArea.entered() onEntered: {
onExited: balancePart1MouseArea.exited() parent.color = MoneroComponents.Style.orange
onClicked: balancePart1MouseArea.clicked(mouse) }
onExited: {
parent.color = MoneroComponents.Style.white
}
onClicked: {
console.log("Copied to clipboard");
clipboard.setText(parent.text);
appWindow.showStatusMessage(qsTr("Copied to clipboard"),3)
}
} }
} }
MoneroComponents.TextPlain {
id: unlockedBalanceText
visible: !(persistentSettings.fiatPriceToggle && persistentSettings.fiatPriceEnabled)
themeTransition: false
anchors.left: parent.left
anchors.leftMargin: 20
anchors.top: parent.top
anchors.topMargin: 126
font.family: "Arial"
color: "#FFFFFF"
text: "N/A"
// dynamically adjust text size
font.pixelSize: {
if (persistentSettings.hideBalance) {
return 20;
}
var digits = text.split('.')[0].length
var defaultSize = 20;
if(digits > 3) {
return defaultSize - 0.6*digits
}
return defaultSize;
}
MouseArea {
hoverEnabled: true
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onEntered: {
parent.color = MoneroComponents.Style.orange
}
onExited: {
parent.color = MoneroComponents.Style.white
}
onClicked: {
console.log("Copied to clipboard");
clipboard.setText(parent.text);
appWindow.showStatusMessage(qsTr("Copied to clipboard"),3)
}
}
}
MoneroComponents.TextPlain {
id: unlockedBalanceTextFiat
themeTransition: false
visible: !unlockedBalanceText.visible
anchors.left: parent.left
anchors.leftMargin: 20
anchors.top: parent.top
anchors.topMargin: 126
font.family: "Arial"
color: "#FFFFFF"
text: "N/A"
font.pixelSize: unlockedBalanceText.font.pixelSize
MouseArea {
hoverEnabled: true
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onEntered: {
parent.color = MoneroComponents.Style.orange
}
onExited: {
parent.color = MoneroComponents.Style.white
}
onClicked: {
console.log("Copied to clipboard");
clipboard.setText(parent.text);
appWindow.showStatusMessage(qsTr("Copied to clipboard"),3)
}
}
}
MoneroComponents.Label {
id: unlockedBalanceLabel
visible: true
text: qsTr("Unlocked balance") + translationManager.emptyString
color: "white"
fontSize: 14
anchors.left: parent.left
anchors.leftMargin: 20
anchors.top: parent.top
anchors.topMargin: 110
themeTransition: false
}
MoneroComponents.Label {
visible: !isMobile
id: balanceLabel
text: qsTr("Balance") + translationManager.emptyString
color: "white"
fontSize: 14
anchors.left: parent.left
anchors.leftMargin: 20
anchors.top: parent.top
anchors.topMargin: 60
elide: Text.ElideRight
textWidth: 238
themeTransition: false
}
Item { //separator Item { //separator
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
@@ -342,7 +420,7 @@ Rectangle {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.top: column1.bottom anchors.top: (isMobile)? parent.top : column1.bottom
color: "transparent" color: "transparent"
Flickable { Flickable {

View File

@@ -34,7 +34,6 @@
#include <QDebug> #include <QDebug>
#include "Logger.h" #include "Logger.h"
#include "src/qt/TailsOS.h"
#include "wallet/api/wallet2_api.h" #include "wallet/api/wallet2_api.h"
// default log path by OS (should be writable) // default log path by OS (should be writable)
@@ -67,9 +66,6 @@ const QString getLogPath(const QString logPath)
{ {
const QFileInfo fi(logPath); const QFileInfo fi(logPath);
if(TailsOS::detect() && TailsOS::usePersistence)
return QDir::homePath() + "/Persistent/Monero/logs/" + defaultLogName;
if(!logPath.isEmpty() && !fi.isDir()) if(!logPath.isEmpty() && !fi.isDir())
return fi.absoluteFilePath(); return fi.absoluteFilePath();
else { else {

View File

@@ -46,6 +46,11 @@ Rectangle {
property Item currentView property Item currentView
property Item previousView property Item previousView
property bool basicMode : isMobile
property string balanceLabelText: qsTr("Balance") + translationManager.emptyString
property string balanceText
property string unlockedBalanceLabelText: qsTr("Unlocked Balance") + translationManager.emptyString
property string unlockedBalanceText
property int minHeight: (appWindow.height > 800) ? appWindow.height : 800 property int minHeight: (appWindow.height > 800) ? appWindow.height : 800
property alias contentHeight: mainFlickable.contentHeight property alias contentHeight: mainFlickable.contentHeight
property alias flickable: mainFlickable property alias flickable: mainFlickable
@@ -204,13 +209,13 @@ Rectangle {
clip: true clip: true
ScrollBar.vertical: ScrollBar { ScrollBar.vertical: ScrollBar {
parent: root parent: mainFlickable.parent
anchors.left: parent.right anchors.left: parent.right
anchors.leftMargin: -14 // 10 margin + 4 scrollbar width anchors.leftMargin: 3
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: persistentSettings.customDecorations ? 60 : 10 anchors.topMargin: 4
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.bottomMargin: persistentSettings.customDecorations ? 15 : 10 anchors.bottomMargin: persistentSettings.customDecorations ? 4 : 0
} }
onFlickingChanged: { onFlickingChanged: {

View File

@@ -9,7 +9,7 @@ Copyright (c) 2014-2019, The Monero Project
- Mail: [dev@getmonero.org](mailto:dev@getmonero.org) - Mail: [dev@getmonero.org](mailto:dev@getmonero.org)
- Github: [https://github.com/monero-project/monero-gui](https://github.com/monero-project/monero-gui) - Github: [https://github.com/monero-project/monero-gui](https://github.com/monero-project/monero-gui)
- IRC: [#monero-dev on Freenode](irc://chat.freenode.net/#monero-dev) - IRC: [#monero-dev on Freenode](irc://chat.freenode.net/#monero-dev)
- Translation platform (Weblate): [translate.getmonero.org](https://translate.getmonero.org) - Translation platform (Pootle): [translate.getmonero.org](https://translate.getmonero.org)
## Vulnerability response ## Vulnerability response
@@ -75,8 +75,6 @@ Packaging for your favorite distribution would be a welcome contribution!
## Compiling the Monero GUI from source ## Compiling the Monero GUI from source
*Note*: Qt 5.9.7 is the minimum version required to build the GUI.
### On Linux: ### On Linux:
(Tested on Ubuntu 17.10 x64, Ubuntu 18.04 x64 and Gentoo x64) (Tested on Ubuntu 17.10 x64, Ubuntu 18.04 x64 and Gentoo x64)
@@ -85,7 +83,7 @@ Packaging for your favorite distribution would be a welcome contribution!
- For Debian distributions (Debian, Ubuntu, Mint, Tails...) - For Debian distributions (Debian, Ubuntu, Mint, Tails...)
`sudo apt install build-essential cmake libboost-all-dev miniupnpc libunbound-dev graphviz doxygen libunwind8-dev pkg-config libssl-dev libzmq3-dev libsodium-dev libhidapi-dev libnorm-dev libusb-1.0-0-dev libpgm-dev` `sudo apt install build-essential cmake libboost-all-dev miniupnpc libunbound-dev graphviz doxygen libunwind8-dev pkg-config libssl-dev libzmq3-dev libsodium-dev libhidapi-dev`
- For Gentoo - For Gentoo
@@ -97,7 +95,7 @@ Packaging for your favorite distribution would be a welcome contribution!
2. Install Qt: 2. Install Qt:
*Note*: The Qt 5.9.7 or newer requirement makes **some** distributions (mostly based on debian, like Ubuntu 16.x or Linux Mint 18.x) obsolete due to their repositories containing an older Qt version. *Note*: Qt 5.9.7 is the minimum version required to build the GUI. This makes **some** distributions (mostly based on debian, like Ubuntu 16.x or Linux Mint 18.x) obsolete due to their repositories containing an older Qt version.
The recommended way is to install 5.9.7 from the [official Qt installer](https://www.qt.io/download-qt-installer) or [compiling it yourself](https://wiki.qt.io/Install_Qt_5_on_Ubuntu). This ensures you have the correct version. Higher versions *can* work but as it differs from our production build target, slight differences may occur. The recommended way is to install 5.9.7 from the [official Qt installer](https://www.qt.io/download-qt-installer) or [compiling it yourself](https://wiki.qt.io/Install_Qt_5_on_Ubuntu). This ensures you have the correct version. Higher versions *can* work but as it differs from our production build target, slight differences may occur.
@@ -167,8 +165,9 @@ The executable can be found in the build/release/bin folder.
5. Add the Qt bin directory to your path 5. Add the Qt bin directory to your path
- Example for Qt: `export PATH=$PATH:$HOME/Qt/5.9.7/clang_64/bin` Example: `export PATH=$PATH:$HOME/Qt/5.9.7/clang_64/bin`
- Example for Homebrew: `export PATH=$PATH:/usr/local/opt/qt/bin`
This is the directory where Qt 5.x is installed on **your** system
6. Grab an up-to-date copy of the monero-gui repository 6. Grab an up-to-date copy of the monero-gui repository

View File

@@ -58,7 +58,7 @@ Item {
RowLayout { RowLayout {
id: checkBoxLayout id: checkBoxLayout
layoutDirection: iconOnTheLeft ? Qt.LeftToRight : Qt.RightToLeft layoutDirection: iconOnTheLeft ? Qt.LeftToRight : Qt.RightToLeft
spacing: 10 spacing: (!isMobile ? 10 : 8)
Item { Item {
id: checkMark id: checkMark

View File

@@ -178,11 +178,7 @@ Window {
onAccepted: { onAccepted: {
if(text.length > 0) { if(text.length > 0) {
textArea.logCommand(">>> " + text) textArea.logCommand(">>> " + text)
daemonManager.sendCommandAsync(text.split(" "), currentWallet.nettype, function(result) { daemonManager.sendCommand(text, currentWallet.nettype);
if (!result) {
appWindow.showStatusMessage(qsTr("Failed to send command"), 3);
}
});
} }
text = "" text = ""
} }

View File

@@ -45,7 +45,6 @@ Item {
property alias horizontalAlignment: label.horizontalAlignment property alias horizontalAlignment: label.horizontalAlignment
property alias elide: label.elide property alias elide: label.elide
property alias textWidth: label.width property alias textWidth: label.width
property alias styleName: label.font.styleName
property alias themeTransition: label.themeTransition property alias themeTransition: label.themeTransition
signal linkActivated() signal linkActivated()
height: label.height height: label.height

View File

@@ -34,6 +34,8 @@ import "../components/effects/" as MoneroEffects
Label { Label {
id: item id: item
fontSize: 18 fontSize: 18
anchors.left: parent.left
anchors.right: parent.right
Rectangle { Rectangle {
anchors.top: item.bottom anchors.top: item.bottom

118
components/MobileHeader.qml Normal file
View File

@@ -0,0 +1,118 @@
import QtQuick 2.9
import QtGraphicalEffects 1.0
import QtQuick.Layouts 1.1
import moneroComponents.Wallet 1.0
import "../components" as MoneroComponents
// BasicPanel header
Rectangle {
id: header
anchors.leftMargin: 1
anchors.rightMargin: 1
Layout.fillWidth: true
Layout.preferredHeight: 64
color: "#FFFFFF"
Image {
id: logo
visible: appWindow.width > 460
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: -5
anchors.left: parent.left
anchors.leftMargin: 50
source: "qrc:///images/moneroLogo2.png"
}
Image {
id: icon
visible: !logo.visible
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: 40
source: "qrc:///images/moneroIcon.png"
}
Grid {
anchors.verticalCenter: parent.verticalCenter
anchors.top: parent.top
anchors.right: parent.right
anchors.topMargin: 10
width: 256
columns: 3
MoneroComponents.TextPlain {
id: balanceLabel
width: 116
height: 20
font.family: "Arial"
font.pixelSize: 12
font.letterSpacing: -1
elide: Text.ElideRight
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignBottom
color: "#535353"
text: leftPanel.balanceLabelText + ":"
}
MoneroComponents.TextPlain {
id: balanceText
width: 110
height: 20
font.family: "Arial"
font.pixelSize: 18
font.letterSpacing: -1
elide: Text.ElideRight
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignBottom
color: "#000000"
text: leftPanel.balanceText
}
Item {
height: 20
width: 20
Image {
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
source: "qrc:///images/lockIcon.png"
}
}
MoneroComponents.TextPlain {
width: 116
height: 20
font.family: "Arial"
font.pixelSize: 12
font.letterSpacing: -1
elide: Text.ElideRight
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignBottom
color: "#535353"
text: qsTr("Unlocked Balance:")
}
MoneroComponents.TextPlain {
id: availableBalanceText
width: 110
height: 20
font.family: "Arial"
font.pixelSize: 14
font.letterSpacing: -1
elide: Text.ElideRight
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignBottom
color: "#000000"
text: leftPanel.unlockedBalanceText
}
}
Rectangle {
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
height: 1
color: "#DBDBDB"
}
}

View File

@@ -29,7 +29,6 @@
import QtQuick 2.9 import QtQuick 2.9
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.1
import FontAwesome 1.0
import moneroComponents.Wallet 1.0 import moneroComponents.Wallet 1.0
import "../components" as MoneroComponents import "../components" as MoneroComponents
@@ -89,7 +88,6 @@ Rectangle {
} }
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
visible: appWindow.walletMode >= 2
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
if(!appWindow.isMining) { if(!appWindow.isMining) {
@@ -135,7 +133,6 @@ Rectangle {
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
visible: appWindow.walletMode >= 2
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
if(!appWindow.isMining) { if(!appWindow.isMining) {
@@ -147,50 +144,6 @@ Rectangle {
} }
} }
} }
Text {
anchors.left: statusTextVal.right
anchors.leftMargin: 16
anchors.verticalCenter: parent.verticalCenter
color: refreshMouseArea.containsMouse ? MoneroComponents.Style.dimmedFontColor : MoneroComponents.Style.defaultFontColor
font.family: FontAwesome.fontFamilySolid
font.pixelSize: 24
font.styleName: "Solid"
opacity: iconItem.opacity * (refreshMouseArea.visible ? 1 : 0.5)
text: FontAwesome.random
visible: (
item.connected != Wallet.ConnectionStatus_Disconnected &&
!persistentSettings.useRemoteNode &&
persistentSettings.bootstrapNodeAddress == "auto"
)
MouseArea {
id: refreshMouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
visible: true
onClicked: {
const callback = function(result) {
refreshMouseArea.visible = true;
if (result) {
appWindow.showStatusMessage(qsTr("Successfully switched to another public node"), 3);
appWindow.currentWallet.refreshHeightAsync();
} else {
appWindow.showStatusMessage(qsTr("Failed to switch public node"), 3);
}
};
daemonManager.sendCommandAsync(
["set_bootstrap_daemon", "auto"],
appWindow.currentWallet.nettype,
callback);
refreshMouseArea.visible = false;
appWindow.showStatusMessage(qsTr("Switching to another public node"), 3);
}
}
}
} }
} }
} }

View File

@@ -0,0 +1,287 @@
// 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.9
import QtQuick.Controls 2.0
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.1
import QtQuick.Controls.Styles 1.4
import QtQuick.Window 2.0
import FontAwesome 1.0
import "../components" as MoneroComponents
Item {
id: root
visible: false
z: parent.z + 2
property bool isHidden: true
property alias password: passwordInput1.text
// same signals as Dialog has
signal accepted()
signal rejected()
signal closeCallback()
function open() {
isHidden = true
passwordInput1.echoMode = TextInput.Password;
passwordInput2.echoMode = TextInput.Password;
inactiveOverlay.visible = true
leftPanel.enabled = false
middlePanel.enabled = false
titleBar.state = "essentials"
root.visible = true;
passwordInput1.text = "";
passwordInput2.text = "";
passwordInput1.focus = true
}
function close() {
inactiveOverlay.visible = false
leftPanel.enabled = true
middlePanel.enabled = true
titleBar.state = "default"
root.visible = false;
closeCallback();
}
function toggleIsHidden() {
passwordInput1.echoMode = isHidden ? TextInput.Normal : TextInput.Password;
passwordInput2.echoMode = isHidden ? TextInput.Normal : TextInput.Password;
isHidden = !isHidden;
}
// TODO: implement without hardcoding sizes
width: 480
height: 360
ColumnLayout {
z: inactiveOverlay.z + 1
id: mainLayout
spacing: 10
anchors { fill: parent; margins: 35 }
ColumnLayout {
id: column
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
Layout.maximumWidth: 400
Label {
text: qsTr("Please enter new password") + translationManager.emptyString
Layout.fillWidth: true
font.pixelSize: 16
font.family: MoneroComponents.Style.fontLight.name
color: MoneroComponents.Style.defaultFontColor
}
TextField {
id : passwordInput1
Layout.topMargin: 6
Layout.fillWidth: true
horizontalAlignment: TextInput.AlignLeft
verticalAlignment: TextInput.AlignVCenter
font.family: MoneroComponents.Style.fontLight.name
font.pixelSize: 24
echoMode: TextInput.Password
bottomPadding: 10
leftPadding: 10
topPadding: 10
color: MoneroComponents.Style.defaultFontColor
selectionColor: MoneroComponents.Style.textSelectionColor
selectedTextColor: MoneroComponents.Style.textSelectedColor
KeyNavigation.tab: passwordInput2
background: Rectangle {
radius: 2
border.color: MoneroComponents.Style.inputBorderColorInActive
border.width: 1
color: MoneroComponents.Style.blackTheme ? "black" : "#A9FFFFFF"
MoneroComponents.Label {
fontSize: 20
text: isHidden ? FontAwesome.eye : FontAwesome.eyeSlash
opacity: 0.7
fontFamily: FontAwesome.fontFamily
anchors.right: parent.right
anchors.rightMargin: 15
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: 1
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
onClicked: {
toggleIsHidden()
}
onEntered: {
parent.opacity = 0.9
parent.fontSize = 24
}
onExited: {
parent.opacity = 0.7
parent.fontSize = 20
}
}
}
}
Keys.onEscapePressed: {
root.close()
root.rejected()
}
}
// padding
Rectangle {
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
height: 10
opacity: 0
color: "black"
}
Label {
text: qsTr("Please confirm new password") + translationManager.emptyString
Layout.fillWidth: true
font.pixelSize: 16
font.family: MoneroComponents.Style.fontLight.name
color: MoneroComponents.Style.defaultFontColor
}
TextField {
id : passwordInput2
Layout.topMargin: 6
Layout.fillWidth: true
horizontalAlignment: TextInput.AlignLeft
verticalAlignment: TextInput.AlignVCenter
font.family: MoneroComponents.Style.fontLight.name
font.pixelSize: 24
echoMode: TextInput.Password
KeyNavigation.tab: okButton
bottomPadding: 10
leftPadding: 10
topPadding: 10
color: MoneroComponents.Style.defaultFontColor
selectionColor: MoneroComponents.Style.textSelectionColor
selectedTextColor: MoneroComponents.Style.textSelectedColor
background: Rectangle {
radius: 2
border.color: MoneroComponents.Style.inputBorderColorInActive
border.width: 1
color: MoneroComponents.Style.blackTheme ? "black" : "#A9FFFFFF"
MoneroComponents.Label {
fontSize: 20
text: isHidden ? FontAwesome.eye : FontAwesome.eyeSlash
opacity: 0.7
fontFamily: FontAwesome.fontFamily
anchors.right: parent.right
anchors.rightMargin: 15
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: 1
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
onClicked: {
toggleIsHidden()
}
onEntered: {
parent.opacity = 0.9
parent.fontSize = 24
}
onExited: {
parent.opacity = 0.7
parent.fontSize = 20
}
}
}
}
Keys.onReturnPressed: {
if (passwordInput1.text === passwordInput2.text) {
root.close()
root.accepted()
}
}
Keys.onEscapePressed: {
root.close()
root.rejected()
}
}
// padding
Rectangle {
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
height: 10
opacity: 0
color: "black"
}
// Ok/Cancel buttons
RowLayout {
id: buttons
spacing: 16
Layout.topMargin: 16
Layout.alignment: Qt.AlignRight
MoneroComponents.StandardButton {
id: cancelButton
text: qsTr("Cancel") + translationManager.emptyString
KeyNavigation.tab: passwordInput1
onClicked: {
root.close()
root.rejected()
}
}
MoneroComponents.StandardButton {
id: okButton
text: qsTr("Continue") + translationManager.emptyString
KeyNavigation.tab: cancelButton
enabled: passwordInput1.text === passwordInput2.text
onClicked: {
root.close()
root.accepted()
}
}
}
}
}
}

View File

@@ -0,0 +1,321 @@
// 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 2.0
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.1
import QtQuick.Controls.Styles 1.4
import QtQuick.Window 2.0
import FontAwesome 1.0
import "../components" as MoneroComponents
Item {
id: root
visible: false
z: parent.z + 2
property bool isHidden: true
property alias passphrase: passphaseInput1.text
property string walletName
property string errorText
// same signals as Dialog has
signal accepted()
signal rejected()
signal closeCallback()
function open(walletName, errorText) {
isHidden = true
passphaseInput1.echoMode = TextInput.Password;
passphaseInput2.echoMode = TextInput.Password;
inactiveOverlay.visible = true
root.walletName = walletName ? walletName : ""
root.errorText = errorText ? errorText : "";
leftPanel.enabled = false
middlePanel.enabled = false
titleBar.state = "essentials"
root.visible = true;
passphaseInput1.text = "";
passphaseInput2.text = "";
passphaseInput1.focus = true
}
function close() {
inactiveOverlay.visible = false
leftPanel.enabled = true
middlePanel.enabled = true
titleBar.state = "default"
root.visible = false;
closeCallback();
}
function toggleIsHidden() {
passphaseInput1.echoMode = isHidden ? TextInput.Normal : TextInput.Password;
passphaseInput2.echoMode = isHidden ? TextInput.Normal : TextInput.Password;
isHidden = !isHidden;
}
function showError(errorText) {
open(root.walletName, errorText);
}
// TODO: implement without hardcoding sizes
width: 480
height: 360
ColumnLayout {
z: inactiveOverlay.z + 1
id: mainLayout
spacing: 10
anchors { fill: parent; margins: 35 }
ColumnLayout {
id: column
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
Layout.maximumWidth: 400
Label {
text: (root.walletName.length > 0 ? qsTr("Please enter wallet device passphrase for: ") + root.walletName : qsTr("Please enter wallet device passphrase")) + translationManager.emptyString
Layout.fillWidth: true
font.pixelSize: 16
font.family: MoneroComponents.Style.fontLight.name
color: MoneroComponents.Style.defaultFontColor
}
Label {
text: qsTr("Warning: passphrase entry on host is a security risk as it can be captured by malware. It is advised to prefer device-based passphrase entry.") + translationManager.emptyString
Layout.fillWidth: true
wrapMode: Text.Wrap
font.pixelSize: 14
font.family: MoneroComponents.Style.fontLight.name
color: MoneroComponents.Style.warningColor
}
Label {
text: root.errorText
visible: root.errorText
color: MoneroComponents.Style.errorColor
font.pixelSize: 16
font.family: MoneroComponents.Style.fontLight.name
Layout.fillWidth: true
wrapMode: Text.Wrap
}
TextField {
id : passphaseInput1
Layout.topMargin: 6
Layout.fillWidth: true
horizontalAlignment: TextInput.AlignLeft
verticalAlignment: TextInput.AlignVCenter
font.family: MoneroComponents.Style.fontLight.name
font.pixelSize: 24
echoMode: TextInput.Password
bottomPadding: 10
leftPadding: 10
topPadding: 10
color: MoneroComponents.Style.defaultFontColor
selectionColor: MoneroComponents.Style.textSelectionColor
selectedTextColor: MoneroComponents.Style.textSelectedColor
KeyNavigation.tab: passphaseInput2
background: Rectangle {
radius: 2
border.color: MoneroComponents.Style.inputBorderColorInActive
border.width: 1
color: MoneroComponents.Style.blackTheme ? "black" : "#A9FFFFFF"
MoneroComponents.Label {
fontSize: 20
text: isHidden ? FontAwesome.eye : FontAwesome.eyeSlash
opacity: 0.7
fontFamily: FontAwesome.fontFamily
anchors.right: parent.right
anchors.rightMargin: 15
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: 1
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
onClicked: {
toggleIsHidden()
}
onEntered: {
parent.opacity = 0.9
parent.fontSize = 24
}
onExited: {
parent.opacity = 0.7
parent.fontSize = 20
}
}
}
}
Keys.onEscapePressed: {
root.close()
root.rejected()
}
}
// padding
Rectangle {
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
height: 10
opacity: 0
color: "transparent"
}
Label {
text: qsTr("Please re-enter") + translationManager.emptyString
Layout.fillWidth: true
font.pixelSize: 16
font.family: MoneroComponents.Style.fontLight.name
color: MoneroComponents.Style.defaultFontColor
}
TextField {
id : passphaseInput2
Layout.topMargin: 6
Layout.fillWidth: true
horizontalAlignment: TextInput.AlignLeft
verticalAlignment: TextInput.AlignVCenter
font.family: MoneroComponents.Style.fontLight.name
font.pixelSize: 24
echoMode: TextInput.Password
KeyNavigation.tab: okButton
bottomPadding: 10
leftPadding: 10
topPadding: 10
color: MoneroComponents.Style.defaultFontColor
selectionColor: MoneroComponents.Style.dimmedFontColor
selectedTextColor: MoneroComponents.Style.defaultFontColor
background: Rectangle {
radius: 2
border.color: MoneroComponents.Style.inputBorderColorInActive
border.width: 1
color: MoneroComponents.Style.blackTheme ? "black" : "#A9FFFFFF"
MoneroComponents.Label {
fontSize: 20
text: isHidden ? FontAwesome.eye : FontAwesome.eyeSlash
opacity: 0.7
fontFamily: FontAwesome.fontFamily
anchors.right: parent.right
anchors.rightMargin: 15
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: 1
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
onClicked: {
toggleIsHidden()
}
onEntered: {
parent.opacity = 0.9
parent.fontSize = 24
}
onExited: {
parent.opacity = 0.7
parent.fontSize = 20
}
}
}
}
Keys.onReturnPressed: {
if (passphaseInput1.text === passphaseInput2.text) {
root.close()
root.accepted()
}
}
Keys.onEscapePressed: {
root.close()
root.rejected()
}
}
// padding
Rectangle {
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
height: 10
opacity: 0
color: "black"
}
// Ok/Cancel buttons
RowLayout {
id: buttons
spacing: 16
Layout.topMargin: 16
Layout.alignment: Qt.AlignRight
MoneroComponents.StandardButton {
id: cancelButton
text: qsTr("Cancel") + translationManager.emptyString
KeyNavigation.tab: passphaseInput1
onClicked: {
root.close()
root.rejected()
}
}
MoneroComponents.StandardButton {
id: okButton
text: qsTr("Continue") + translationManager.emptyString
KeyNavigation.tab: cancelButton
enabled: passphaseInput1.text === passphaseInput2.text
onClicked: {
root.close()
root.accepted()
}
}
}
}
}
}

View File

@@ -44,63 +44,34 @@ Item {
z: parent.z + 2 z: parent.z + 2
property bool isHidden: true property bool isHidden: true
property alias password: passwordInput1.text property alias password: passwordInput.text
property string walletName property string walletName
property string errorText property string errorText
property bool passwordDialogMode property bool shiftIsPressed: false
property bool passphraseDialogMode property bool isCapsLocksActive: false
property bool newPasswordDialogMode property bool backspaceIsPressed: false
// same signals as Dialog has // same signals as Dialog has
signal accepted() signal accepted()
signal acceptedNewPassword()
signal acceptedPassphrase()
signal rejected() signal rejected()
signal rejectedNewPassword()
signal rejectedPassphrase()
signal closeCallback() signal closeCallback()
function _openInit(walletName, errorText) { function open(walletName, errorText) {
isHidden = true isHidden = true
capsLockTextLabel.visible = oshelper.isCapsLock(); passwordInput.echoMode = TextInput.Password
passwordInput1.echoMode = TextInput.Password passwordInput.text = ""
passwordInput2.echoMode = TextInput.Password passwordInput.forceActiveFocus();
passwordInput1.text = ""
passwordInput2.text = ""
passwordInput1.forceActiveFocus();
inactiveOverlay.visible = true // draw appwindow inactive inactiveOverlay.visible = true // draw appwindow inactive
root.walletName = walletName ? walletName : "" root.walletName = walletName ? walletName : ""
errorTextLabel.text = errorText ? errorText : ""; errorTextLabel.text = errorText ? errorText : "";
leftPanel.enabled = false leftPanel.enabled = false
middlePanel.enabled = false middlePanel.enabled = false
wizard.enabled = false
titleBar.state = "essentials" titleBar.state = "essentials"
root.visible = true; root.visible = true;
appWindow.hideBalanceForced = true; appWindow.hideBalanceForced = true;
appWindow.updateBalance(); appWindow.updateBalance();
} }
function open(walletName, errorText) {
passwordDialogMode = true;
passphraseDialogMode = false;
newPasswordDialogMode = false;
_openInit(walletName, errorText);
}
function openPassphraseDialog() {
passwordDialogMode = false;
passphraseDialogMode = true;
newPasswordDialogMode = false;
_openInit("", "");
}
function openNewPasswordDialog() {
passwordDialogMode = false;
passphraseDialogMode = false;
newPasswordDialogMode = true;
_openInit("", "");
}
function showError(errorText) { function showError(errorText) {
open(root.walletName, errorText); open(root.walletName, errorText);
} }
@@ -109,7 +80,6 @@ Item {
inactiveOverlay.visible = false inactiveOverlay.visible = false
leftPanel.enabled = true leftPanel.enabled = true
middlePanel.enabled = true middlePanel.enabled = true
wizard.enabled = true
titleBar.state = "default" titleBar.state = "default"
root.visible = false; root.visible = false;
@@ -118,12 +88,6 @@ Item {
closeCallback(); closeCallback();
} }
function toggleIsHidden() {
passwordInput1.echoMode = isHidden ? TextInput.Normal : TextInput.Password;
passwordInput2.echoMode = isHidden ? TextInput.Normal : TextInput.Password;
isHidden = !isHidden;
}
ColumnLayout { ColumnLayout {
z: inactiveOverlay.z + 1 z: inactiveOverlay.z + 1
id: mainLayout id: mainLayout
@@ -138,14 +102,7 @@ Item {
Layout.maximumWidth: 400 Layout.maximumWidth: 400
Label { Label {
text: { text: (root.walletName.length > 0 ? qsTr("Please enter wallet password for: ") + root.walletName : qsTr("Please enter wallet password")) + translationManager.emptyString
if (newPasswordDialogMode) {
return qsTr("Please enter new wallet password") + translationManager.emptyString;
} else {
var device = passwordDialogMode ? qsTr("wallet password") : qsTr("wallet device passphrase");
return (root.walletName.length > 0 ? qsTr("Please enter %1 for: ").arg(device) + root.walletName : qsTr("Please enter %1").arg(device)) + translationManager.emptyString;
}
}
Layout.fillWidth: true Layout.fillWidth: true
font.pixelSize: 16 font.pixelSize: 16
@@ -154,41 +111,19 @@ Item {
color: MoneroComponents.Style.defaultFontColor color: MoneroComponents.Style.defaultFontColor
} }
Label {
text: qsTr("Warning: passphrase entry on host is a security risk as it can be captured by malware. It is advised to prefer device-based passphrase entry.") + translationManager.emptyString
visible: passphraseDialogMode
Layout.fillWidth: true
wrapMode: Text.Wrap
font.pixelSize: 14
font.family: MoneroComponents.Style.fontLight.name
color: MoneroComponents.Style.warningColor
}
Label { Label {
id: errorTextLabel id: errorTextLabel
visible: root.errorText || text !== "" visible: root.errorText || text !== ""
color: MoneroComponents.Style.errorColor
font.pixelSize: 16
font.family: MoneroComponents.Style.fontLight.name
Layout.fillWidth: true
wrapMode: Text.Wrap
}
Label {
id: capsLockTextLabel
visible: false
color: MoneroComponents.Style.errorColor color: MoneroComponents.Style.errorColor
font.pixelSize: 16 font.pixelSize: 16
font.family: MoneroComponents.Style.fontLight.name font.family: MoneroComponents.Style.fontLight.name
Layout.fillWidth: true Layout.fillWidth: true
wrapMode: Text.Wrap wrapMode: Text.Wrap
text: qsTr("CAPSLOCKS IS ON.") + translationManager.emptyString;
} }
TextField { TextField {
id: passwordInput1 id : passwordInput
Layout.topMargin: 6 Layout.topMargin: 6
Layout.fillWidth: true Layout.fillWidth: true
horizontalAlignment: TextInput.AlignLeft horizontalAlignment: TextInput.AlignLeft
@@ -196,20 +131,24 @@ Item {
font.family: MoneroComponents.Style.fontLight.name font.family: MoneroComponents.Style.fontLight.name
font.pixelSize: 24 font.pixelSize: 24
echoMode: TextInput.Password echoMode: TextInput.Password
KeyNavigation.tab: { KeyNavigation.tab: okButton
if (passwordDialogMode) {
return okButton
} else {
return passwordInput2
}
}
bottomPadding: 10 bottomPadding: 10
leftPadding: 10 leftPadding: 10
topPadding: 10 topPadding: 10
color: MoneroComponents.Style.defaultFontColor color: MoneroComponents.Style.defaultFontColor
selectionColor: MoneroComponents.Style.textSelectionColor selectionColor: MoneroComponents.Style.textSelectionColor
selectedTextColor: MoneroComponents.Style.textSelectedColor selectedTextColor: MoneroComponents.Style.textSelectedColor
onTextChanged: capsLockTextLabel.visible = oshelper.isCapsLock();
onTextChanged: {
var letter = text[passwordInput.text.length - 1];
isCapsLocksActive = Utils.isUpperLock(shiftIsPressed, letter);
if(isCapsLocksActive && !backspaceIsPressed){
errorTextLabel.text = qsTr("CAPSLOCKS IS ON.") + translationManager.emptyString;
}
else{
errorTextLabel.text = "";
}
}
background: Rectangle { background: Rectangle {
radius: 2 radius: 2
@@ -238,7 +177,8 @@ Item {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
hoverEnabled: true hoverEnabled: true
onClicked: { onClicked: {
toggleIsHidden(); passwordInput.echoMode = isHidden ? TextInput.Normal : TextInput.Password;
isHidden = !isHidden;
} }
onEntered: { onEntered: {
parent.opacity = 0.9 parent.opacity = 0.9
@@ -255,129 +195,28 @@ Item {
Keys.enabled: root.visible Keys.enabled: root.visible
Keys.onReturnPressed: { Keys.onReturnPressed: {
root.close() root.close()
if (passwordDialogMode) { root.accepted()
root.accepted()
} else if (newPasswordDialogMode) {
root.acceptedNewPassword()
} else if (passphraseDialogMode) {
root.acceptedPassphrase()
}
} }
Keys.onEscapePressed: { Keys.onEscapePressed: {
root.close() root.close()
if (passwordDialogMode) { root.rejected()
root.rejected() }
} else if (newPasswordDialogMode) { Keys.onPressed: {
root.rejectedNewPassword() if(event.key === Qt.Key_Shift){
} else if (passphraseDialogMode) { shiftIsPressed = true;
root.rejectedPassphrase() }
if(event.key === Qt.Key_Backspace){
backspaceIsPressed = true;
} }
} }
} Keys.onReleased: {
if(event.key === Qt.Key_Shift){
// padding shiftIsPressed = false;
Rectangle { }
visible: !passwordDialogMode if(event.key === Qt.Key_Backspace){
Layout.fillWidth: true backspaceIsPressed =false;
Layout.alignment: Qt.AlignHCenter
height: 10
opacity: 0
color: "black"
}
Label {
visible: !passwordDialogMode
text: newPasswordDialogMode ? qsTr("Please confirm new password") : qsTr("Please confirm wallet device passphrase") + translationManager.emptyString
Layout.fillWidth: true
font.pixelSize: 16
font.family: MoneroComponents.Style.fontLight.name
color: MoneroComponents.Style.defaultFontColor
}
TextField {
id: passwordInput2
visible: !passwordDialogMode
Layout.topMargin: 6
Layout.fillWidth: true
horizontalAlignment: TextInput.AlignLeft
verticalAlignment: TextInput.AlignVCenter
font.family: MoneroComponents.Style.fontLight.name
font.pixelSize: 24
echoMode: TextInput.Password
KeyNavigation.tab: okButton
bottomPadding: 10
leftPadding: 10
topPadding: 10
color: MoneroComponents.Style.defaultFontColor
selectionColor: MoneroComponents.Style.textSelectionColor
selectedTextColor: MoneroComponents.Style.textSelectedColor
onTextChanged: capsLockTextLabel.visible = oshelper.isCapsLock();
background: Rectangle {
radius: 2
border.color: MoneroComponents.Style.inputBorderColorInActive
border.width: 1
color: MoneroComponents.Style.blackTheme ? "black" : "#A9FFFFFF"
MoneroComponents.Label {
fontSize: 20
text: isHidden ? FontAwesome.eye : FontAwesome.eyeSlash
opacity: 0.7
fontFamily: FontAwesome.fontFamily
anchors.right: parent.right
anchors.rightMargin: 15
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: 1
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
onClicked: {
toggleIsHidden()
}
onEntered: {
parent.opacity = 0.9
parent.fontSize = 24
}
onExited: {
parent.opacity = 0.7
parent.fontSize = 20
}
}
} }
} }
Keys.onReturnPressed: {
if (passwordInput1.text === passwordInput2.text) {
root.close()
if (newPasswordDialogMode) {
root.acceptedNewPassword()
} else if (passphraseDialogMode) {
root.acceptedPassphrase()
}
}
}
Keys.onEscapePressed: {
root.close()
if (newPasswordDialogMode) {
root.rejectedNewPassword()
} else if (passphraseDialogMode) {
root.rejectedPassphrase()
}
}
}
// padding
Rectangle {
visible: !passwordDialogMode
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
height: 10
opacity: 0
color: "black"
} }
// Ok/Cancel buttons // Ok/Cancel buttons
@@ -390,38 +229,26 @@ Item {
MoneroComponents.StandardButton { MoneroComponents.StandardButton {
id: cancelButton id: cancelButton
small: true small: true
text: qsTr("Cancel") + translationManager.emptyString text: root.walletName.length > 0 ? qsTr("Change wallet") + translationManager.emptyString : qsTr("Cancel") + translationManager.emptyString
KeyNavigation.tab: passwordInput1 KeyNavigation.tab: passwordInput
onClicked: { onClicked: {
root.close() root.close()
if (passwordDialogMode) { root.rejected()
root.rejected()
} else if (newPasswordDialogMode) {
root.rejectedNewPassword()
} else if (passphraseDialogMode) {
root.rejectedPassphrase()
}
} }
} }
MoneroComponents.StandardButton { MoneroComponents.StandardButton {
id: okButton id: okButton
small: true small: true
text: qsTr("Ok") + translationManager.emptyString text: qsTr("Continue") + translationManager.emptyString
KeyNavigation.tab: cancelButton KeyNavigation.tab: cancelButton
enabled: (passwordDialogMode == true) ? true : passwordInput1.text === passwordInput2.text
onClicked: { onClicked: {
root.close() root.close()
if (passwordDialogMode) { root.accepted()
root.accepted()
} else if (newPasswordDialogMode) {
root.acceptedNewPassword()
} else if (passphraseDialogMode) {
root.acceptedPassphrase()
}
} }
} }
} }
} }
} }
} }

View File

@@ -74,7 +74,7 @@ Item {
MoneroComponents.TextPlain { MoneroComponents.TextPlain {
id: label id: label
Layout.leftMargin: 10 Layout.leftMargin: (!isMobile ? 10 : 8)
color: MoneroComponents.Style.defaultFontColor color: MoneroComponents.Style.defaultFontColor
font.family: MoneroComponents.Style.fontRegular.name font.family: MoneroComponents.Style.fontRegular.name
font.pixelSize: radioButton.fontSize font.pixelSize: radioButton.fontSize

View File

@@ -35,7 +35,7 @@ import "../js/Utils.js" as Utils
import "../components" as MoneroComponents import "../components" as MoneroComponents
GridLayout { GridLayout {
columns: 2 columns: (isMobile) ? 1 : 2
columnSpacing: 32 columnSpacing: 32
id: root id: root
property alias daemonAddrText: daemonAddr.text property alias daemonAddrText: daemonAddr.text

View File

@@ -82,8 +82,10 @@ Rectangle {
function open() { function open() {
// Center // Center
root.x = parent.width/2 - root.width/2 if(!isMobile) {
root.y = 100 root.x = parent.width/2 - root.width/2
root.y = 100
}
root.z = 11 root.z = 11
root.visible = true; root.visible = true;
} }
@@ -94,14 +96,14 @@ Rectangle {
} }
// TODO: implement without hardcoding sizes // TODO: implement without hardcoding sizes
width: 520 width: isMobile ? screenWidth : 520
height: 380 height: isMobile ? screenHeight : 380
ColumnLayout { ColumnLayout {
id: mainLayout id: mainLayout
spacing: 10 spacing: 10
anchors.fill: parent anchors.fill: parent
anchors.margins: 20 anchors.margins: (isMobile? 17 : 20)
RowLayout { RowLayout {
id: column id: column

View File

@@ -51,6 +51,7 @@ QtObject {
property string titleBarBackgroundBorderColor: blackTheme ? _b_titleBarBackgroundBorderColor : _w_titleBarBackgroundBorderColor property string titleBarBackgroundBorderColor: blackTheme ? _b_titleBarBackgroundBorderColor : _w_titleBarBackgroundBorderColor
property string titleBarLogoSource: blackTheme ? _b_titleBarLogoSource : _w_titleBarLogoSource property string titleBarLogoSource: blackTheme ? _b_titleBarLogoSource : _w_titleBarLogoSource
property string titleBarMinimizeSource: blackTheme ? _b_titleBarMinimizeSource : _w_titleBarMinimizeSource property string titleBarMinimizeSource: blackTheme ? _b_titleBarMinimizeSource : _w_titleBarMinimizeSource
property string titleBarExpandSource: blackTheme ? _b_titleBarExpandSource : _w_titleBarExpandSource
property string titleBarFullscreenSource: blackTheme ? _b_titleBarFullscreenSource : _w_titleBarFullscreenSource property string titleBarFullscreenSource: blackTheme ? _b_titleBarFullscreenSource : _w_titleBarFullscreenSource
property string titleBarCloseSource: blackTheme ? _b_titleBarCloseSource : _w_titleBarCloseSource property string titleBarCloseSource: blackTheme ? _b_titleBarCloseSource : _w_titleBarCloseSource
property string titleBarButtonHoverColor: blackTheme ? _b_titleBarButtonHoverColor : _w_titleBarButtonHoverColor property string titleBarButtonHoverColor: blackTheme ? _b_titleBarButtonHoverColor : _w_titleBarButtonHoverColor
@@ -107,6 +108,7 @@ QtObject {
property string _b_titleBarBackgroundBorderColor: "#2f2f2f" property string _b_titleBarBackgroundBorderColor: "#2f2f2f"
property string _b_titleBarLogoSource: "qrc:///images/titlebarLogo.png" property string _b_titleBarLogoSource: "qrc:///images/titlebarLogo.png"
property string _b_titleBarMinimizeSource: "qrc:///images/minimize.svg" property string _b_titleBarMinimizeSource: "qrc:///images/minimize.svg"
property string _b_titleBarExpandSource: "qrc:///images/sidebar.svg"
property string _b_titleBarFullscreenSource: "qrc:///images/fullscreen.svg" property string _b_titleBarFullscreenSource: "qrc:///images/fullscreen.svg"
property string _b_titleBarCloseSource: "qrc:///images/close.svg" property string _b_titleBarCloseSource: "qrc:///images/close.svg"
property string _b_titleBarButtonHoverColor: "#10FFFFFF" property string _b_titleBarButtonHoverColor: "#10FFFFFF"
@@ -163,6 +165,7 @@ QtObject {
property string _w_titleBarBackgroundBorderColor: "#DEDEDE" property string _w_titleBarBackgroundBorderColor: "#DEDEDE"
property string _w_titleBarLogoSource: "qrc:///images/themes/white/titlebarLogo.png" property string _w_titleBarLogoSource: "qrc:///images/themes/white/titlebarLogo.png"
property string _w_titleBarMinimizeSource: "qrc:///images/themes/white/minimize.svg" property string _w_titleBarMinimizeSource: "qrc:///images/themes/white/minimize.svg"
property string _w_titleBarExpandSource: "qrc:///images/themes/white/expand.svg"
property string _w_titleBarFullscreenSource: "qrc:///images/themes/white/fullscreen.svg" property string _w_titleBarFullscreenSource: "qrc:///images/themes/white/fullscreen.svg"
property string _w_titleBarCloseSource: "qrc:///images/themes/white/close.svg" property string _w_titleBarCloseSource: "qrc:///images/themes/white/close.svg"
property string _w_titleBarButtonHoverColor: "#11000000" property string _w_titleBarButtonHoverColor: "#11000000"

View File

@@ -38,14 +38,14 @@ import "effects/" as MoneroEffects
Rectangle { Rectangle {
id: root id: root
property int mouseX: 0 property int mouseX: 0
property bool basicButtonVisible: false
property bool customDecorations: persistentSettings.customDecorations property bool customDecorations: persistentSettings.customDecorations
property bool showMinimizeButton: true property bool showMinimizeButton: true
property bool showMaximizeButton: true property bool showMaximizeButton: true
property bool showCloseButton: true property bool showCloseButton: true
property string walletName: ""
height: { height: {
if(!persistentSettings.customDecorations) return 0; if(!persistentSettings.customDecorations || isMobile) return 0;
return 50; return 50;
} }
@@ -56,18 +56,18 @@ Rectangle {
signal maximizeClicked signal maximizeClicked
signal minimizeClicked signal minimizeClicked
signal languageClicked signal languageClicked
signal closeWalletClicked signal goToBasicVersion(bool yes)
state: "default" state: "default"
states: [ states: [
State { State {
name: "default"; name: "default";
PropertyChanges { target: btnCloseWallet; visible: true} PropertyChanges { target: btnSidebarCollapse; visible: true}
PropertyChanges { target: btnLanguageToggle; visible: true} PropertyChanges { target: btnLanguageToggle; visible: true}
}, State { }, State {
// show only theme switcher and window controls // show only theme switcher and window controls
name: "essentials"; name: "essentials";
PropertyChanges { target: btnCloseWallet; visible: false} PropertyChanges { target: btnSidebarCollapse; visible: false}
PropertyChanges { target: btnLanguageToggle; visible: false} PropertyChanges { target: btnLanguageToggle; visible: false}
} }
] ]
@@ -93,20 +93,22 @@ Rectangle {
// collapse sidebar // collapse sidebar
Rectangle { Rectangle {
id: btnCloseWallet id: btnSidebarCollapse
visible: root.basicButtonVisible
color: "transparent" color: "transparent"
Layout.preferredWidth: parent.height Layout.preferredWidth: parent.height
Layout.preferredHeight: parent.height Layout.preferredHeight: parent.height
MoneroEffects.ImageMask {
Text {
text: FontAwesome.signOutAlt
font.family: FontAwesome.fontFamilySolid
font.pixelSize: 16
color: MoneroComponents.Style.defaultFontColor
font.styleName: "Solid"
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
height: 14
width: 14
image: MoneroComponents.Style.titleBarExpandSource
color: MoneroComponents.Style.defaultFontColor
fontAwesomeFallbackIcon: FontAwesome.cube
fontAwesomeFallbackSize: 14
fontAwesomeFallbackOpacity: MoneroComponents.Style.blackTheme ? 1.0 : 0.9
opacity: 0.75 opacity: 0.75
} }
@@ -116,7 +118,7 @@ Rectangle {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onEntered: parent.color = MoneroComponents.Style.titleBarButtonHoverColor onEntered: parent.color = MoneroComponents.Style.titleBarButtonHoverColor
onExited: parent.color = "transparent" onExited: parent.color = "transparent"
onClicked: root.closeWalletClicked(leftPanel.visible) onClicked: root.goToBasicVersion(leftPanel.visible)
} }
} }
@@ -129,10 +131,9 @@ Rectangle {
Text { Text {
text: FontAwesome.globe text: FontAwesome.globe
font.family: FontAwesome.fontFamilySolid font.family: FontAwesome.fontFamily
font.pixelSize: 16 font.pixelSize: 16
color: MoneroComponents.Style.defaultFontColor color: MoneroComponents.Style.defaultFontColor
font.styleName: "Solid"
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
opacity: 0.75 opacity: 0.75
@@ -155,10 +156,9 @@ Rectangle {
Layout.preferredHeight: parent.height Layout.preferredHeight: parent.height
Text { Text {
text: FontAwesome.moonO text: MoneroComponents.Style.blackTheme ? FontAwesome.lightbulbO : FontAwesome.moonO
font.family: MoneroComponents.Style.blackTheme ? FontAwesome.fontFamilySolid : FontAwesome.fontFamily font.family: FontAwesome.fontFamily
font.styleName: MoneroComponents.Style.blackTheme ? "Solid" : "Regular" font.pixelSize: 16
font.pixelSize: 15
color: MoneroComponents.Style.defaultFontColor color: MoneroComponents.Style.defaultFontColor
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
@@ -189,7 +189,6 @@ Rectangle {
// monero logo // monero logo
Item { Item {
visible: walletName.length === 0
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: parent.height Layout.preferredHeight: parent.height
@@ -217,22 +216,6 @@ Rectangle {
} }
} }
Item {
visible: walletName.length > 0
Layout.fillWidth: true
Layout.preferredHeight: parent.height
MoneroComponents.TextPlain {
font.pixelSize: 20
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
width: parent.width
height: parent.height
elide: Text.ElideRight
text: walletName
}
}
// minimize // minimize
Rectangle { Rectangle {
color: "transparent" color: "transparent"

View File

@@ -41,8 +41,6 @@ Item {
property string color: "" property string color: ""
property bool fontAwesomeFallbackEnabled: true property bool fontAwesomeFallbackEnabled: true
property var fontAwesomeFallbackIcon: "" property var fontAwesomeFallbackIcon: ""
property string fontAwesomeFallbackFont: FontAwesome.fontFamilySolid
property string fontAwesomeFallbackStyle: "Solid"
property int fontAwesomeFallbackSize: 16 property int fontAwesomeFallbackSize: 16
property double fontAwesomeFallbackOpacity: 0.8 property double fontAwesomeFallbackOpacity: 0.8
property string fontAwesomeFallbackColor: MoneroComponents.Style.defaultFontColor property string fontAwesomeFallbackColor: MoneroComponents.Style.defaultFontColor
@@ -76,9 +74,8 @@ Item {
id: fontAwesomeFallback id: fontAwesomeFallback
visible: !isOpenGL && root.fontAwesomeFallback visible: !isOpenGL && root.fontAwesomeFallback
text: !isOpenGL ? root.fontAwesomeFallbackIcon : "" text: !isOpenGL ? root.fontAwesomeFallbackIcon : ""
font.family: root.fontAwesomeFallbackFont font.family: FontAwesome.fontFamily
font.pixelSize: root.fontAwesomeFallbackSize font.pixelSize: root.fontAwesomeFallbackSize
font.styleName: root.fontAwesomeFallbackStyle
color: root.fontAwesomeFallbackColor color: root.fontAwesomeFallbackColor
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter

View File

@@ -4,23 +4,10 @@ import QtQuick 2.9
Object { Object {
FontLoader { FontLoader {
id: regular source: "./fontawesome-webfont.ttf"
source: "./fa-regular-400.ttf"
} }
FontLoader { property string fontFamily: "FontAwesome"
id: brands
source: "./fa-brands-400.ttf"
}
FontLoader {
id: solid
source: "./fa-solid-900.ttf"
}
property string fontFamily: regular.name
property string fontFamilyBrands: brands.name
property string fontFamilySolid: solid.name
// Icons // Icons
property string addressBook : "\uf2b9" property string addressBook : "\uf2b9"
@@ -607,7 +594,6 @@ Object {
property string shower : "\uf2cc" property string shower : "\uf2cc"
property string signIn : "\uf090" property string signIn : "\uf090"
property string signLanguage : "\uf2a7" property string signLanguage : "\uf2a7"
property string signOutAlt : "\uf2f5"
property string signOut : "\uf08b" property string signOut : "\uf08b"
property string signal : "\uf012" property string signal : "\uf012"
property string signing : "\uf2a7" property string signing : "\uf2a7"

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -17,7 +17,7 @@ if [ ! -d $MONERO_DIR/src ]; then
fi fi
git submodule update --remote git submodule update --remote
git -C $MONERO_DIR fetch git -C $MONERO_DIR fetch
git -C $MONERO_DIR checkout v0.15.0.0 git -C $MONERO_DIR checkout v0.14.1.0
# get monero core tag # get monero core tag
pushd $MONERO_DIR pushd $MONERO_DIR
@@ -253,7 +253,4 @@ if [ -d $MONERO_DIR/build/$BUILD_TYPE/external/unbound ]; then
popd popd
fi fi
# install randomx
eval make -C $MONERO_DIR/build/$BUILD_TYPE/external/randomx all install
popd popd

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

BIN
images/card-background.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
images/card-background@2x.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 419 B

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 436 B

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 612 B

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="27" height="27" viewBox="0 0 27 27">
<g fill="none" fill-rule="evenodd" stroke="#FFF" stroke-linecap="round" stroke-width="1.25">
<path d="M1.595 2.19h5.357v5.358"/>
<path d="M6.682 3.021A12.49 12.49 0 0 0 1 13.5C1 20.404 6.596 26 13.5 26S26 20.404 26 13.5 20.404 1 13.5 1"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 359 B

View File

@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="27" viewBox="0 0 22 27">
<g fill="none" fill-rule="evenodd" stroke="#FFF" stroke-linecap="round" stroke-width="1.071">
<path d="M20.412 7.818h-6.47v-6.25"/>
<path d="M21 26H1V1h12.941L21 7.818z"/>
<path d="M7.154 15.404l3.333-3.333 3.334 3.334M10.487 20.286v-7.548"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 371 B

6
images/sidebar.svg Normal file
View File

@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18">
<g fill="none" fill-rule="evenodd" stroke="#FFF" stroke-width="1.636" opacity="1">
<rect width="16.364" height="16.364" x=".818" y=".818" rx="1.636"/>
<path fill="#FFF" d="M6.182 17.182V.818H1.64a.822.822 0 0 0-.822.822v14.72c0 .454.368.822.822.822h4.542z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 379 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

View File

@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14">
<g fill="none" fill-rule="evenodd" opacity="1">
<path fill="none" d="M-11-11h36v36h-36z" opacity="1"/>
<path stroke="#000" stroke-linecap="round" stroke-width="1.556" d="M13 13L1.686 1.686M1 7.222V1h6.222"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 328 B

View File

@@ -1,30 +0,0 @@
# Building the Installer Deterministically
This file contains info about building the Windows installer deterministically, i.e. how different people on different Windows machines or VMs can build it and arrive at a result that is bit-for-bit identical. This approach is also known as *reproducible builds*, see e.g. [this Wikipedia article](https://en.wikipedia.org/wiki/Reproducible_builds).
The steps to build the Windows installer deterministically by a group of people are the following (for some details about the build process in general see `README.md`):
* Agree on a particular version of Inno Setup, and everybody install that
* Get the zip file for the Windows GUI wallet and unpack it, plus make sure / check that the file timestamps are preserved, i.e. upacked timestamp = timestamp in zip file
* Build using Inno Setup and the `Monero.iss` script file
* Success: All people arrive at a bit-for-bit identical installer .exe file, which they can verify by calculating and exchanging SHA256 hashes
Some background info why this process is relatively simple:
The tool used to build the Windows installer, Inno Setup, avoids many issues that make reproducible builds very challenging with many other compilers and similar tools: It does not store current date and time in the installer .exe file, and it does not seem to depend on the Windows version it runs on (tried with Windows 7 and two different editions of Windows 10), nor on the locale and display language.
So fortunately no complicated things as faked current system time or use of VMs with exactly prescribed versions of Windows are necessary.
The version of Inno Setup **is** important however: People wanting to reproducibly build the installer must agree on a particular version to use. This should not be hard to do however.
Also important are the **timestamps** of the source files because they go into the installer file, to be restored at install time.
You would think timestamp preservation is no problem when unpacking the zip archive with the files for the Windows GUI wallet from getmonero.org, but if you use the zip folder unpack functionality of the Windows 7 GUI, the files get the current date, **not** the file recorded in the zip file. (The Windows 10 GUI seems better here, and also the 7zip app.)
In any case, after unpacking, check the file dates in the `bin` directory where the installer script looks for them with the dates of the files in the zip file: They must be identical.
Note that the the following line in `Monero.iss` is also important regarding file timestamps:
TimeStampsInUTC=yes
Without this line the **timezone** of the machine used to build the installer would matter, with different timezones leading to different installer files.

View File

@@ -1,4 +1,4 @@
; Monero Carbon Chamaeleon GUI Wallet Installer for Windows ; Monero Boron Butterfly GUI Wallet Installer for Windows
; Copyright (c) 2017-2019, The Monero Project ; Copyright (c) 2017-2019, The Monero Project
; See LICENSE ; See LICENSE
@@ -8,7 +8,7 @@ AppName=Monero GUI Wallet
; Thus it's important to keep this stable over releases ; Thus it's important to keep this stable over releases
; With a different "AppName" InnoSetup would treat a mere update as a completely new application and thus mess up ; With a different "AppName" InnoSetup would treat a mere update as a completely new application and thus mess up
AppVersion=0.15.0.0 AppVersion=0.14.1.0
DefaultDirName={pf}\Monero GUI Wallet DefaultDirName={pf}\Monero GUI Wallet
DefaultGroupName=Monero GUI Wallet DefaultGroupName=Monero GUI Wallet
UninstallDisplayIcon={app}\monero-wallet-gui.exe UninstallDisplayIcon={app}\monero-wallet-gui.exe
@@ -21,8 +21,6 @@ DisableWelcomePage=no
LicenseFile=LICENSE LicenseFile=LICENSE
AppPublisher=The Monero Developer Community AppPublisher=The Monero Developer Community
AppPublisherURL=https://getmonero.org AppPublisherURL=https://getmonero.org
TimeStampsInUTC=yes
CompressionThreads=1
UsedUserAreasWarning=no UsedUserAreasWarning=no
; The above directive silences the following compiler warning: ; The above directive silences the following compiler warning:
@@ -58,7 +56,7 @@ Name: "en"; MessagesFile: "compiler:Default.isl"
; .exe/.dll file possibly with version info). ; .exe/.dll file possibly with version info).
; ;
; This is far more robust than relying on version info or on file dates (flag "comparetimestamp"). ; This is far more robust than relying on version info or on file dates (flag "comparetimestamp").
; As of version 0.15.0.0, the Monero .exe files do not carry version info anyway in their .exe headers. ; As of version 0.14.1.0, the Monero .exe files do not carry version info anyway in their .exe headers.
; The only small drawback seems to be somewhat longer update times because each and every file is ; The only small drawback seems to be somewhat longer update times because each and every file is
; copied again, even if already present with correct file date and identical content. ; copied again, even if already present with correct file date and identical content.
; ;
@@ -70,7 +68,7 @@ Source: "FinishImage.bmp"; Flags: dontcopy
; Monero GUI wallet exe and guide ; Monero GUI wallet exe and guide
Source: "bin\monero-wallet-gui.exe"; DestDir: "{app}"; Flags: ignoreversion Source: "bin\monero-wallet-gui.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "bin\monero-gui-wallet-guide.pdf"; DestDir: "{app}"; Flags: ignoreversion Source: "bin\monero-GUI-guide.pdf"; DestDir: "{app}"; Flags: ignoreversion
; Monero CLI wallet ; Monero CLI wallet
Source: "bin\monero-wallet-cli.exe"; DestDir: "{app}"; Flags: ignoreversion Source: "bin\monero-wallet-cli.exe"; DestDir: "{app}"; Flags: ignoreversion
@@ -197,7 +195,7 @@ begin
// Additional wizard page for entering a special blockchain location // Additional wizard page for entering a special blockchain location
blockChainDefaultDir := ExpandConstant('{commonappdata}\bitmonero'); blockChainDefaultDir := ExpandConstant('{commonappdata}\bitmonero');
s := 'The default folder to store the Monero blockchain is ' + blockChainDefaultDir; s := 'The default folder to store the Monero blockchain is ' + blockChainDefaultDir;
s := s + '. As this will need more than 74 GB of free space, you may want to use a folder on a different drive.'; s := s + '. As this will need more than 70 GB of free space, you may want to use a folder on a different drive.';
s := s + ' If yes, specify that folder here.'; s := s + ' If yes, specify that folder here.';
BlockChainDirPage := CreateInputDirPage(wpSelectDir, BlockChainDirPage := CreateInputDirPage(wpSelectDir,

View File

@@ -6,7 +6,7 @@ Copyright (c) 2017-2019, The Monero Project
This is a *Inno Setup* script `Monero.iss` plus some related files This is a *Inno Setup* script `Monero.iss` plus some related files
that allows you to build a standalone Windows installer (.exe) for that allows you to build a standalone Windows installer (.exe) for
the GUI wallet that comes with the Carbon Chamaeleon release of Monero. the GUI wallet that comes with the Boron Butterfly release of Monero.
This turns the GUI wallet into a more or less standard Windows program, This turns the GUI wallet into a more or less standard Windows program,
by default installed into a subdirectory of `C:\Program Files`, a by default installed into a subdirectory of `C:\Program Files`, a
@@ -18,7 +18,7 @@ Monero.
As the setup script in file [Monero.iss](Monero.iss) has to list many As the setup script in file [Monero.iss](Monero.iss) has to list many
files and directories of the GUI wallet package to install by name, files and directories of the GUI wallet package to install by name,
this version of the script only works with exactly the GUI wallet this version of the script only works with exactly the GUI wallet
for Monero release *Carbon Chamaeleon* that you find on for Monero release *Boron Butterfly* that you find on
[the official download page](https://getmonero.org/downloads/). [the official download page](https://getmonero.org/downloads/).
It should however be easy to modify the script for future It should however be easy to modify the script for future
@@ -32,15 +32,13 @@ See [LICENSE](LICENSE).
You can only build on Windows, and the result is always a You can only build on Windows, and the result is always a
Windows .exe file that can act as a standalone installer for the Windows .exe file that can act as a standalone installer for the
Carbon Chamaeleon GUI wallet. Boron Butterfly GUI wallet.
Note that the installer build process is now reproducible / deterministic. For details check the file [Deterministic.md](Deterministic.md).
The build steps in detail: The build steps in detail:
1. Install *Inno Setup*. You can get it from [here](http://www.jrsoftware.org/isdl.php) 1. Install *Inno Setup*. You can get it from [here](http://www.jrsoftware.org/isdl.php)
2. Get the Inno Setup script plus related files by cloning the whole [monero-gui GitHub repository](https://github.com/monero-project/monero-gui); you will only need the files in the installer directory `installers\windows` however. Depending on development state, additionally instead of simply using `master` you may have to checkout a specific branch, like `release-v0.15`. 2. Get the Inno Setup script plus related files by cloning the whole [monero-gui GitHub repository](https://github.com/monero-project/monero-gui); you will only need the files in the installer directory `installers\windows` however. Depending on development state, additionally you may have to checkout a specific branch, like `release-v0.14`.
3. The setup script is written to take the GUI wallet files from a subdirectory named `bin`; so create `installers\windows\bin`, get the zip file of the GUI wallet from [here](https://getmonero.org/downloads/), unpack it somewhere, and copy all the files and subdirectories in the single subdirectory there (currently named `monero-gui-0.15.0.0`) to this `bin` subdirectory 3. The setup script is written to take the GUI wallet files from a subdirectory named `bin`; so create `installers\windows\bin`, get the zip file of the GUI wallet from [here](https://getmonero.org/downloads/), unpack it somewhere, and copy all the files and subdirectories in the single subdirectory there (currently named `monero-gui-0.14.1.0`) to this `bin` subdirectory
4. Start Inno Setup, load `Monero.iss` and compile it 4. Start Inno Setup, load `Monero.iss` and compile it
5. The result i.e. the finished installer will be the file `mysetup.exe` in the `installers\windows\Output` subdirectory 5. The result i.e. the finished installer will be the file `mysetup.exe` in the `installers\windows\Output` subdirectory

View File

@@ -1,13 +1,13 @@
<html> <html>
<head> <head>
<title>Monero Carbon Chamaeleon GUI Wallet</title> <title>Monero Boron Butterfly GUI Wallet</title>
</head> </head>
<body style="font-family: Arial, Helvetica, sans-serif"> <body style="font-family: Arial, Helvetica, sans-serif">
<h1>Monero Carbon Chamaeleon GUI Wallet</h1> <h1>Monero Boron Butterfly GUI Wallet</h1>
<p>Copyright (c) 2014-2019, The Monero Project<br> <p>Copyright (c) 2014-2019, The Monero Project<br>
Date: November 1, 2019</p> Date: May 7, 2019</p>
<h2>Preface</h2> <h2>Preface</h2>
@@ -23,7 +23,7 @@
<h2>Content of the Package</h2> <h2>Content of the Package</h2>
<p>You just installed the <i>Monero GUI wallet</i> for Windows, release Carbon Chamaeleon, version 0.15.0.0. <p>You just installed the <i>Monero GUI wallet</i> for Windows, release Boron Butterfly, version 0.14.1.0.
The wallet enables you to send and receive Moneroj in a secure and very private way. The wallet enables you to send and receive Moneroj in a secure and very private way.
</p> </p>
@@ -61,7 +61,7 @@
provides the most security and privacy possible for you.</p> provides the most security and privacy possible for you.</p>
<p>However if your Internet access makes it difficult to run a full node, or if you have simply no room to store <p>However if your Internet access makes it difficult to run a full node, or if you have simply no room to store
the blockchain locally (somewhat over 74 GB in November 2019, and of course growing), you can compromise and try to connect the blockchain locally (somewhat over 70 GB in May 2019, and of course growing), you can compromise and try to connect
to a remote node. One way of finding such a node is checking to a remote node. One way of finding such a node is checking
<a href="https://moneroworld.com/#nodes">this page</a>. <a href="https://moneroworld.com/#nodes">this page</a>.
</p> </p>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 440 KiB

After

Width:  |  Height:  |  Size: 440 KiB

View File

@@ -0,0 +1 @@
-----

View File

@@ -12,13 +12,13 @@ function destinationsToAddress(destinations){
} }
function addressTruncate(address, range){ function addressTruncate(address, range){
if(typeof(address) === "undefined") return ""; if(typeof(address) === "undefined") return;
if(typeof(range) === "undefined") range = 8; if(typeof(range) === "undefined") range = 8;
return address.substring(0, range) + "..." + address.substring(address.length-range); return address.substring(0, range) + "..." + address.substring(address.length-range);
} }
function addressTruncatePretty(address, blocks){ function addressTruncatePretty(address, blocks){
if(typeof(address) === "undefined") return ""; if(typeof(address) === "undefined") return;
if(typeof(blocks) === "undefined") blocks = 2; if(typeof(blocks) === "undefined") blocks = 2;
blocks = blocks <= 1 ? 1 : blocks >= 23 ? 23 : blocks; blocks = blocks <= 1 ? 1 : blocks >= 23 ? 23 : blocks;
var ret = ""; var ret = "";

View File

@@ -46,6 +46,7 @@ function showSeedPage() {
leftPanel.selectItem(middlePanel.state); leftPanel.selectItem(middlePanel.state);
} }
passwordDialog.open(); passwordDialog.open();
if(isMobile) hideMenu();
updateBalance(); updateBalance();
} }
@@ -93,6 +94,16 @@ function netTypeToString(){
return nettype == 1 ? qsTr("Testnet") : nettype == 2 ? qsTr("Stagenet") : qsTr("Mainnet"); return nettype == 1 ? qsTr("Testnet") : nettype == 2 ? qsTr("Stagenet") : qsTr("Mainnet");
} }
function randomChoice(arr){
return arr[Math.floor(Math.random() * arr.length)];
}
function filterNodes(nodes, port) {
if(typeof data === 'number')
port = port.toString();
return nodes.filter(function(_){return _.indexOf(port) !== -1});
}
function epoch(){ function epoch(){
return Math.floor((new Date).getTime()/1000); return Math.floor((new Date).getTime()/1000);
} }
@@ -101,6 +112,25 @@ function roundDownToNearestThousand(_num){
return Math.floor(_num/1000.0)*1000 return Math.floor(_num/1000.0)*1000
} }
function isAlpha(letter){ return letter.match(/^[A-Za-z0-9]+$/) !== null; }
function isLowerCaseChar(letter){ return letter === letter.toLowerCase(); }
function isUpperLock(shift, letter){
if(!isAlpha((letter))) return false;
if(shift) {
if(isLowerCaseChar(letter))
return true;
else
return false;
} else {
if(isLowerCaseChar(letter))
return false;
else
return true;
}
}
function qmlEach(item, properties, ignoredObjectNames, arr){ function qmlEach(item, properties, ignoredObjectNames, arr){
// Traverse QML object tree and return components that match // Traverse QML object tree and return components that match
// via property names. Similar to jQuery("myclass").each(... // via property names. Similar to jQuery("myclass").each(...
@@ -133,3 +163,15 @@ function capitalize(s){
if (typeof s !== 'string') return '' if (typeof s !== 'string') return ''
return s.charAt(0).toUpperCase() + s.slice(1) return s.charAt(0).toUpperCase() + s.slice(1)
} }
function formatMoney(n, c, d, t) {
// https://stackoverflow.com/a/149099
var c = isNaN(c = Math.abs(c)) ? 2 : c,
d = d == undefined ? "." : d,
t = t == undefined ? "," : t,
s = n < 0 ? "-" : "",
i = String(parseInt(n = Math.abs(Number(n) || 0).toFixed(c))),
j = (j = i.length) > 3 ? j % 3 : 0;
return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : "");
};

View File

@@ -39,8 +39,10 @@ function switchPage(next) {
console.log("switchpage: currentPage: ", currentPage); console.log("switchpage: currentPage: ", currentPage);
// Update prev/next button positions for mobile/desktop // Update prev/next button positions for mobile/desktop
prevButton.anchors.verticalCenter = wizard.verticalCenter prevButton.anchors.verticalCenter = (!isMobile) ? wizard.verticalCenter : undefined
nextButton.anchors.verticalCenter = wizard.verticalCenter prevButton.anchors.bottom = (isMobile) ? wizard.bottom : undefined
nextButton.anchors.verticalCenter = (!isMobile) ? wizard.verticalCenter : undefined
nextButton.anchors.bottom = (isMobile) ? wizard.bottom : undefined
if (currentPage > 0 || currentPage < pages.length - 1) { if (currentPage > 0 || currentPage < pages.length - 1) {
pages[currentPage].opacity = 0 pages[currentPage].opacity = 0

View File

@@ -51,12 +51,4 @@ SCRIPT_DIR="\$(dirname "\$(test -L "\${BASH_SOURCE[0]}" && readlink "\${BASH_SOU
"\$SCRIPT_DIR"/$GUI_EXEC "\$@" "\$SCRIPT_DIR"/$GUI_EXEC "\$@"
EOL EOL
# Create start script
cat > $TARGET/start-tails.AppImage <<EOL
#!/bin/bash
# Silly hack to provide a launcher that is double clickable
bash ./start-gui.sh
EOL
chmod +x $TARGET/start-gui.sh chmod +x $TARGET/start-gui.sh
chmod +x $TARGET/start-tails.AppImage

View File

@@ -64,9 +64,8 @@
#include "MainApp.h" #include "MainApp.h"
#include "qt/ipc.h" #include "qt/ipc.h"
#include "qt/utils.h" #include "qt/utils.h"
#include "src/qt/TailsOS.h" #include "qt/mime.h"
#include "src/qt/KeysFiles.h" #include "src/qt/KeysFiles.h"
#include "src/qt/MoneroSettings.h"
#include "qt/prices.h" #include "qt/prices.h"
// IOS exclusions // IOS exclusions
@@ -83,7 +82,6 @@ bool isAndroid = false;
bool isWindows = false; bool isWindows = false;
bool isMac = false; bool isMac = false;
bool isLinux = false; bool isLinux = false;
bool isTails = false;
bool isDesktop = false; bool isDesktop = false;
bool isOpenGL = true; bool isOpenGL = true;
@@ -103,7 +101,6 @@ int main(int argc, char *argv[])
bool isWindows = true; bool isWindows = true;
#elif defined(Q_OS_LINUX) #elif defined(Q_OS_LINUX)
bool isLinux = true; bool isLinux = true;
bool isTails = TailsOS::detect();
#elif defined(Q_OS_MAC) #elif defined(Q_OS_MAC)
bool isMac = true; bool isMac = true;
#endif #endif
@@ -125,43 +122,25 @@ int main(int argc, char *argv[])
// qDebug() << "High DPI auto scaling - enabled"; // qDebug() << "High DPI auto scaling - enabled";
//#endif //#endif
// Turn off colors in monerod log output.
qputenv("TERM", "goaway");
MainApp app(argc, argv);
app.setApplicationName("monero-core");
app.setOrganizationDomain("getmonero.org");
app.setOrganizationName("monero-project");
// Ask to enable Tails OS persistence mode, it affects:
// - Log file location
// - QML Settings file location (monero-core.conf)
// - Default wallets path
// Target directory is: ~/Persistent/Monero
if (isTails) {
if (!TailsOS::detectDataPersistence())
TailsOS::showDataPersistenceDisabledWarning();
else
TailsOS::askPersistence();
}
QString moneroAccountsDir; QString moneroAccountsDir;
#if defined(Q_OS_WIN) || defined(Q_OS_IOS) #if defined(Q_OS_WIN) || defined(Q_OS_IOS)
QStringList moneroAccountsRootDir = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation); QStringList moneroAccountsRootDir = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation);
#else #else
QStringList moneroAccountsRootDir = QStandardPaths::standardLocations(QStandardPaths::HomeLocation); QStringList moneroAccountsRootDir = QStandardPaths::standardLocations(QStandardPaths::HomeLocation);
#endif #endif
if (!moneroAccountsRootDir.empty()) {
if(isTails && TailsOS::usePersistence){
moneroAccountsDir = QDir::homePath() + "/Persistent/Monero/wallets";
} else if (!moneroAccountsRootDir.empty()) {
moneroAccountsDir = moneroAccountsRootDir.at(0) + "/Monero/wallets"; moneroAccountsDir = moneroAccountsRootDir.at(0) + "/Monero/wallets";
} else { } else {
qCritical() << "Error: accounts root directory could not be set"; qCritical() << "Error: accounts root directory could not be set";
return 1; return 1;
} }
MainApp app(argc, argv);
app.setApplicationName("monero-core");
app.setOrganizationDomain("getmonero.org");
app.setOrganizationName("monero-project");
#if defined(Q_OS_LINUX) #if defined(Q_OS_LINUX)
if (isDesktop) app.setWindowIcon(QIcon(":/images/appicon.ico")); if (isDesktop) app.setWindowIcon(QIcon(":/images/appicon.ico"));
#endif #endif
@@ -194,7 +173,6 @@ int main(int argc, char *argv[])
} }
qWarning().noquote() << "app startd" << "(log: " + logPath + ")"; qWarning().noquote() << "app startd" << "(log: " + logPath + ")";
// Desktop entry
#ifdef Q_OS_LINUX #ifdef Q_OS_LINUX
registerXdgMime(app); registerXdgMime(app);
#endif #endif
@@ -246,9 +224,6 @@ int main(int argc, char *argv[])
// registering types for QML // registering types for QML
qmlRegisterType<clipboardAdapter>("moneroComponents.Clipboard", 1, 0, "Clipboard"); qmlRegisterType<clipboardAdapter>("moneroComponents.Clipboard", 1, 0, "Clipboard");
// Temporary Qt.labs.settings replacement
qmlRegisterType<MoneroSettings>("moneroComponents.Settings", 1, 0, "MoneroSettings");
qmlRegisterUncreatableType<Wallet>("moneroComponents.Wallet", 1, 0, "Wallet", "Wallet can't be instantiated directly"); qmlRegisterUncreatableType<Wallet>("moneroComponents.Wallet", 1, 0, "Wallet", "Wallet can't be instantiated directly");
@@ -338,8 +313,6 @@ int main(int argc, char *argv[])
engine.rootContext()->setContextProperty("walletLogPath", logPath); engine.rootContext()->setContextProperty("walletLogPath", logPath);
engine.rootContext()->setContextProperty("tailsUsePersistence", TailsOS::usePersistence);
// Exclude daemon manager from IOS // Exclude daemon manager from IOS
#ifndef Q_OS_IOS #ifndef Q_OS_IOS
const QStringList arguments = (QStringList) QCoreApplication::arguments().at(0); const QStringList arguments = (QStringList) QCoreApplication::arguments().at(0);
@@ -353,7 +326,7 @@ int main(int argc, char *argv[])
engine.rootContext()->setContextProperty("isIOS", isIOS); engine.rootContext()->setContextProperty("isIOS", isIOS);
engine.rootContext()->setContextProperty("isAndroid", isAndroid); engine.rootContext()->setContextProperty("isAndroid", isAndroid);
engine.rootContext()->setContextProperty("isOpenGL", isOpenGL); engine.rootContext()->setContextProperty("isOpenGL", isOpenGL);
engine.rootContext()->setContextProperty("isTails", isTails); engine.rootContext()->setContextProperty("isLinux", isLinux);
engine.rootContext()->setContextProperty("screenWidth", geo.width()); engine.rootContext()->setContextProperty("screenWidth", geo.width());
engine.rootContext()->setContextProperty("screenHeight", geo.height()); engine.rootContext()->setContextProperty("screenHeight", geo.height());
@@ -377,7 +350,6 @@ int main(int argc, char *argv[])
accountName = "My monero Account"; accountName = "My monero Account";
engine.rootContext()->setContextProperty("defaultAccountName", accountName); engine.rootContext()->setContextProperty("defaultAccountName", accountName);
engine.rootContext()->setContextProperty("homePath", QDir::homePath());
engine.rootContext()->setContextProperty("applicationDirectory", QApplication::applicationDirPath()); engine.rootContext()->setContextProperty("applicationDirectory", QApplication::applicationDirPath());
engine.rootContext()->setContextProperty("idealThreadCount", QThread::idealThreadCount()); engine.rootContext()->setContextProperty("idealThreadCount", QThread::idealThreadCount());

527
main.qml
View File

@@ -31,11 +31,11 @@ import QtQuick.Window 2.0
import QtQuick.Controls 1.1 import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1 import QtQuick.Controls.Styles 1.1
import QtQuick.Dialogs 1.2 import QtQuick.Dialogs 1.2
import Qt.labs.settings 1.0
import moneroComponents.Wallet 1.0 import moneroComponents.Wallet 1.0
import moneroComponents.PendingTransaction 1.0 import moneroComponents.PendingTransaction 1.0
import moneroComponents.NetworkType 1.0 import moneroComponents.NetworkType 1.0
import moneroComponents.Settings 1.0
import "components" import "components"
import "components" as MoneroComponents import "components" as MoneroComponents
@@ -69,6 +69,7 @@ ApplicationWindow {
property bool foundNewBlock: false property bool foundNewBlock: false
property bool qrScannerEnabled: (typeof builtWithScanner != "undefined") && builtWithScanner property bool qrScannerEnabled: (typeof builtWithScanner != "undefined") && builtWithScanner
property int blocksToSync: 1 property int blocksToSync: 1
property var isMobile: (appWindow.width > 700 && !isAndroid) ? false : true
property bool isMining: false property bool isMining: false
property int walletMode: persistentSettings.walletMode property int walletMode: persistentSettings.walletMode
property var cameraUi property var cameraUi
@@ -105,6 +106,19 @@ ApplicationWindow {
} }
} }
property string remoteNodeService: {
// support user-defined remote node aggregators
if(persistentSettings.remoteNodeService){
var service = persistentSettings.remoteNodeService;
if(service.charAt(service.length-1) !== "/")
service += "/";
return service;
}
// monero-gui workgroup maintained
return "https://autonode.xmr.pm/"
}
// true if wallet ever synchronized // true if wallet ever synchronized
property bool walletInitialized : false property bool walletInitialized : false
@@ -225,6 +239,7 @@ ApplicationWindow {
if (typeof currentWallet !== "undefined" && currentWallet !== null) { if (typeof currentWallet !== "undefined" && currentWallet !== null) {
console.log("Daemon change - closing " + currentWallet) console.log("Daemon change - closing " + currentWallet)
closeWallet(); closeWallet();
currentWallet = undefined
} else if (!walletInitialized) { } else if (!walletInitialized) {
// set page to transfer if not changing daemon // set page to transfer if not changing daemon
middlePanel.state = "Transfer"; middlePanel.state = "Transfer";
@@ -268,46 +283,31 @@ ApplicationWindow {
titleBar.visible = persistentSettings.customDecorations; titleBar.visible = persistentSettings.customDecorations;
} }
function closeWallet(callback) { function closeWallet() {
// Disconnect all listeners // Disconnect all listeners
if (typeof currentWallet === "undefined" || currentWallet === null) { if (typeof currentWallet !== "undefined" && currentWallet !== null) {
if (callback) { currentWallet.heightRefreshed.disconnect(onHeightRefreshed);
callback(); currentWallet.refreshed.disconnect(onWalletRefresh)
} currentWallet.updated.disconnect(onWalletUpdate)
return; currentWallet.newBlock.disconnect(onWalletNewBlock)
currentWallet.moneySpent.disconnect(onWalletMoneySent)
currentWallet.moneyReceived.disconnect(onWalletMoneyReceived)
currentWallet.unconfirmedMoneyReceived.disconnect(onWalletUnconfirmedMoneyReceived)
currentWallet.transactionCreated.disconnect(onTransactionCreated)
currentWallet.connectionStatusChanged.disconnect(onWalletConnectionStatusChanged)
currentWallet.deviceButtonRequest.disconnect(onDeviceButtonRequest);
currentWallet.deviceButtonPressed.disconnect(onDeviceButtonPressed);
currentWallet.transactionCommitted.disconnect(onTransactionCommitted);
middlePanel.paymentClicked.disconnect(handlePayment);
middlePanel.sweepUnmixableClicked.disconnect(handleSweepUnmixable);
middlePanel.getProofClicked.disconnect(handleGetProof);
middlePanel.checkProofClicked.disconnect(handleCheckProof);
} }
currentWallet.heightRefreshed.disconnect(onHeightRefreshed);
currentWallet.refreshed.disconnect(onWalletRefresh)
currentWallet.updated.disconnect(onWalletUpdate)
currentWallet.newBlock.disconnect(onWalletNewBlock)
currentWallet.moneySpent.disconnect(onWalletMoneySent)
currentWallet.moneyReceived.disconnect(onWalletMoneyReceived)
currentWallet.unconfirmedMoneyReceived.disconnect(onWalletUnconfirmedMoneyReceived)
currentWallet.transactionCreated.disconnect(onTransactionCreated)
currentWallet.connectionStatusChanged.disconnect(onWalletConnectionStatusChanged)
currentWallet.deviceButtonRequest.disconnect(onDeviceButtonRequest);
currentWallet.deviceButtonPressed.disconnect(onDeviceButtonPressed);
currentWallet.transactionCommitted.disconnect(onTransactionCommitted);
middlePanel.paymentClicked.disconnect(handlePayment);
middlePanel.sweepUnmixableClicked.disconnect(handleSweepUnmixable);
middlePanel.getProofClicked.disconnect(handleGetProof);
middlePanel.checkProofClicked.disconnect(handleCheckProof);
appWindow.walletName = "";
currentWallet = undefined; currentWallet = undefined;
walletManager.closeWallet();
appWindow.showProcessingSplash(qsTr("Closing wallet..."));
if (callback) {
walletManager.closeWalletAsync(function() {
hideProcessingSplash();
callback();
});
} else {
walletManager.closeWallet();
hideProcessingSplash();
}
} }
function connectWallet(wallet) { function connectWallet(wallet) {
@@ -335,6 +335,7 @@ ApplicationWindow {
} }
walletName = usefulName(wallet.path) walletName = usefulName(wallet.path)
updateSyncing(false)
viewOnly = currentWallet.viewOnly; viewOnly = currentWallet.viewOnly;
@@ -375,21 +376,11 @@ ApplicationWindow {
currentDaemonAddress = localDaemonAddress currentDaemonAddress = localDaemonAddress
console.log("initializing with daemon address: ", currentDaemonAddress) console.log("initializing with daemon address: ", currentDaemonAddress)
currentWallet.initAsync( currentWallet.initAsync(currentDaemonAddress, 0, persistentSettings.is_recovering, persistentSettings.is_recovering_from_device, persistentSettings.restore_height);
currentDaemonAddress,
isTrustedDaemon(),
0,
persistentSettings.is_recovering,
persistentSettings.is_recovering_from_device,
persistentSettings.restore_height);
// save wallet keys in case wallet settings have been changed in the init // save wallet keys in case wallet settings have been changed in the init
currentWallet.setPassword(walletPassword); currentWallet.setPassword(walletPassword);
} }
function isTrustedDaemon() {
return !persistentSettings.useRemoteNode || persistentSettings.is_trusted_daemon;
}
function walletPath() { function walletPath() {
var wallet_path = persistentSettings.wallet_path var wallet_path = persistentSettings.wallet_path
return wallet_path; return wallet_path;
@@ -406,22 +397,24 @@ ApplicationWindow {
if (!currentWallet) if (!currentWallet)
return; return;
var balance = "?.??"; var balance_unlocked = qsTr("HIDDEN");
var balanceU = "?.??"; var balance = qsTr("HIDDEN");
if(!hideBalanceForced && !persistentSettings.hideBalance){ if(!hideBalanceForced && !persistentSettings.hideBalance){
balance_unlocked = walletManager.displayAmount(currentWallet.unlockedBalance(currentWallet.currentSubaddressAccount));
balance = walletManager.displayAmount(currentWallet.balance(currentWallet.currentSubaddressAccount)); balance = walletManager.displayAmount(currentWallet.balance(currentWallet.currentSubaddressAccount));
balanceU = walletManager.displayAmount(currentWallet.unlockedBalance(currentWallet.currentSubaddressAccount));
} }
middlePanel.unlockedBalanceText = balance_unlocked;
leftPanel.unlockedBalanceText = balance_unlocked;
middlePanel.balanceText = balance;
leftPanel.balanceText = balance;
if (persistentSettings.fiatPriceEnabled) { if (persistentSettings.fiatPriceEnabled) {
appWindow.fiatApiUpdateBalance(balance); appWindow.fiatApiUpdateBalance(balance, balance_unlocked);
} }
leftPanel.minutesToUnlock = (balance !== balanceU) ? currentWallet.history.minutesToUnlock : ""; var accountLabel = currentWallet.getSubaddressLabel(currentWallet.currentSubaddressAccount, 0);
leftPanel.currentAccountIndex = currentWallet.currentSubaddressAccount; leftPanel.balanceLabelText = qsTr("Balance (#%1%2)").arg(currentWallet.currentSubaddressAccount).arg(accountLabel === "" ? "" : (" " + accountLabel));
leftPanel.currentAccountLabel = currentWallet.getSubaddressLabel(currentWallet.currentSubaddressAccount, 0);
leftPanel.balanceString = balance
leftPanel.balanceUnlockedString = balanceU
} }
function onUriHandler(uri){ function onUriHandler(uri){
@@ -460,6 +453,10 @@ ApplicationWindow {
// Raise window // Raise window
appWindow.raise(); appWindow.raise();
appWindow.show(); appWindow.show();
// @TODO: remove after paymentID deprecation
if(params.hasOwnProperty("tx_payment_id"))
persistentSettings.showPid = true;
} }
} }
@@ -469,19 +466,15 @@ ApplicationWindow {
leftPanel.networkStatus.connected = status leftPanel.networkStatus.connected = status
// update local daemon status. // update local daemon status.
if(walletManager.isDaemonLocal(currentDaemonAddress)) if(!isMobile && walletManager.isDaemonLocal(currentDaemonAddress))
daemonRunning = status; daemonRunning = status;
// Update fee multiplier dropdown on transfer page // Update fee multiplier dropdown on transfer page
middlePanel.transferView.updatePriorityDropdown(); middlePanel.transferView.updatePriorityDropdown();
// If wallet isnt connected, advanced wallet mode and no daemon is running - Ask // If wallet isnt connected, advanced wallet mode and no daemon is running - Ask
if (appWindow.walletMode >= 2 && walletManager.isDaemonLocal(currentDaemonAddress) && !walletInitialized && status === Wallet.ConnectionStatus_Disconnected) { if(!isMobile && appWindow.walletMode >= 2 && walletManager.isDaemonLocal(currentDaemonAddress) && !walletInitialized && status === Wallet.ConnectionStatus_Disconnected && !daemonManager.running(persistentSettings.nettype)){
daemonManager.runningAsync(persistentSettings.nettype, function(running) { daemonManagerDialog.open();
if (!running) {
daemonManagerDialog.open();
}
});
} }
// initialize transaction history once wallet is initialized first time; // initialize transaction history once wallet is initialized first time;
if (!walletInitialized) { if (!walletInitialized) {
@@ -565,21 +558,26 @@ ApplicationWindow {
} }
} }
function onWalletClosed(walletAddress) {
hideProcessingSplash();
console.log(">>> wallet closed: " + walletAddress)
}
function onWalletPassphraseNeeded(){ function onWalletPassphraseNeeded(){
if(rootItem.state !== "normal") return; if(rootItem.state !== "normal") return;
hideProcessingSplash(); hideProcessingSplash();
console.log(">>> wallet passphrase needed: ") console.log(">>> wallet passphrase needed: ")
passwordDialog.onAcceptedPassphraseCallback = function() { passphraseDialog.onAcceptedCallback = function() {
walletManager.onPassphraseEntered(passwordDialog.password); walletManager.onPassphraseEntered(passphraseDialog.passphrase);
this.onWalletOpening(); this.onWalletOpening();
} }
passwordDialog.onRejectedPassphraseCallback = function() { passphraseDialog.onRejectedCallback = function() {
walletManager.onPassphraseEntered("", true); walletManager.onPassphraseEntered("", true);
this.onWalletOpening(); this.onWalletOpening();
} }
passwordDialog.openPassphraseDialog() passphraseDialog.open()
} }
function onWalletUpdate() { function onWalletUpdate() {
@@ -590,6 +588,8 @@ ApplicationWindow {
foundNewBlock = false; foundNewBlock = false;
console.log("New block found - updating history") console.log("New block found - updating history")
currentWallet.history.refresh(currentWallet.currentSubaddressAccount) currentWallet.history.refresh(currentWallet.currentSubaddressAccount)
var timeToUnlock = currentWallet.history.minutesToUnlock
leftPanel.minutesToUnlockTxt = (timeToUnlock > 0)? (timeToUnlock == 20)? qsTr("Unlocked balance (waiting for block)") : qsTr("Unlocked balance (~%1 min)").arg(timeToUnlock) : qsTr("Unlocked balance");
if(middlePanel.state == "History") if(middlePanel.state == "History")
middlePanel.historyView.update(); middlePanel.historyView.update();
@@ -600,7 +600,7 @@ ApplicationWindow {
console.log("connecting remote node"); console.log("connecting remote node");
persistentSettings.useRemoteNode = true; persistentSettings.useRemoteNode = true;
currentDaemonAddress = persistentSettings.remoteNodeAddress; currentDaemonAddress = persistentSettings.remoteNodeAddress;
currentWallet.initAsync(currentDaemonAddress, isTrustedDaemon()); currentWallet.initAsync(currentDaemonAddress);
walletManager.setDaemonAddressAsync(currentDaemonAddress); walletManager.setDaemonAddressAsync(currentDaemonAddress);
} }
@@ -611,7 +611,7 @@ ApplicationWindow {
console.log("disconnecting remote node"); console.log("disconnecting remote node");
persistentSettings.useRemoteNode = false; persistentSettings.useRemoteNode = false;
currentDaemonAddress = localDaemonAddress currentDaemonAddress = localDaemonAddress
currentWallet.initAsync(currentDaemonAddress, isTrustedDaemon()); currentWallet.initAsync(currentDaemonAddress);
walletManager.setDaemonAddressAsync(currentDaemonAddress); walletManager.setDaemonAddressAsync(currentDaemonAddress);
} }
@@ -633,7 +633,7 @@ ApplicationWindow {
} }
// Update wallet sync progress // Update wallet sync progress
leftPanel.isSyncing = (currentWallet.connected() !== Wallet.ConnectionStatus_Disconnected) && !daemonSynced updateSyncing((currentWallet.connected() !== Wallet.ConnectionStatus_Disconnected) && !daemonSynced)
// Update transfer page status // Update transfer page status
middlePanel.updateStatus(); middlePanel.updateStatus();
@@ -683,8 +683,8 @@ ApplicationWindow {
simpleModeConnectionTimer.stop(); simpleModeConnectionTimer.stop();
appWindow.showProcessingSplash(qsTr("Waiting for daemon to start...")) appWindow.showProcessingSplash(qsTr("Waiting for daemon to start..."))
const noSync = appWindow.walletMode === 0; daemonManager.start(flags, persistentSettings.nettype, persistentSettings.blockchainDataDir, persistentSettings.bootstrapNodeAddress);
daemonManager.start(flags, persistentSettings.nettype, persistentSettings.blockchainDataDir, persistentSettings.bootstrapNodeAddress, noSync); persistentSettings.daemonFlags = flags
} }
function stopDaemon(){ function stopDaemon(){
@@ -700,7 +700,6 @@ ApplicationWindow {
// resume refresh // resume refresh
currentWallet.startRefresh(); currentWallet.startRefresh();
// resume simplemode connection timer // resume simplemode connection timer
appWindow.disconnectedEpoch = Utils.epoch();
simpleModeConnectionTimer.start(); simpleModeConnectionTimer.start();
} }
function onDaemonStopped(){ function onDaemonStopped(){
@@ -838,9 +837,7 @@ ApplicationWindow {
", priority: ", priority, ", priority: ", priority,
", description: ", description); ", description: ", description);
var splashMsg = qsTr("Creating transaction..."); showProcessingSplash("Creating transaction");
splashMsg += appWindow.currentWallet.isLedger() ? qsTr("\n\nPlease check your hardware wallet \nyour input may be required.") : "";
showProcessingSplash(splashMsg);
transactionDescription = description; transactionDescription = description;
@@ -1078,6 +1075,12 @@ ApplicationWindow {
informationPopup.open() informationPopup.open()
} }
function updateSyncing(syncing) {
var text = (syncing ? qsTr("Balance (syncing)") : qsTr("Balance")) + translationManager.emptyString
leftPanel.balanceLabelText = text
middlePanel.balanceLabelText = text
}
// blocks UI if wallet can't be opened or no connection to the daemon // blocks UI if wallet can't be opened or no connection to the daemon
function enableUI(enable) { function enableUI(enable) {
middlePanel.enabled = enable; middlePanel.enabled = enable;
@@ -1102,27 +1105,37 @@ ApplicationWindow {
console.log("Hiding processing splash") console.log("Hiding processing splash")
splash.close(); splash.close();
if (!passwordDialog.visible) { leftPanel.enabled = true
leftPanel.enabled = true middlePanel.enabled = true
middlePanel.enabled = true titleBar.enabled = true
titleBar.enabled = true inactiveOverlay.visible = false;
inactiveOverlay.visible = false;
}
} }
// close wallet and show wizard // close wallet and show wizard
function showWizard(){ function showWizard(){
clearMoneroCardLabelText();
walletInitialized = false; walletInitialized = false;
closeWallet(function() { closeWallet();
wizard.restart(); currentWallet = undefined;
wizard.wizardState = "wizardHome"; wizard.restart();
rootItem.state = "wizard" wizard.wizardState = "wizardHome";
// reset balance rootItem.state = "wizard"
clearMoneroCardLabelText(); // reset balance
// disable timers leftPanel.balanceText = leftPanel.unlockedBalanceText = walletManager.displayAmount(0);
userInActivityTimer.running = false; fiatApiUpdateBalance(0, 0);
simpleModeConnectionTimer.running = false; // disable timers
}); userInActivityTimer.running = false;
simpleModeConnectionTimer.running = false;
}
function hideMenu() {
goToBasicAnimation.start();
console.log(appWindow.width)
}
function showMenu() {
goToProAnimation.start();
console.log(appWindow.width)
} }
@@ -1241,19 +1254,22 @@ ApplicationWindow {
Prices.getJSON(url); Prices.getJSON(url);
} }
function fiatApiUpdateBalance(balance){ function fiatApiUpdateBalance(balance, unlocked_balance){
// update balance card // update balance card
var ticker = persistentSettings.fiatPriceCurrency === "xmrusd" ? appWindow.fiatPriceXMRUSD : appWindow.fiatPriceXMREUR; var ticker = persistentSettings.fiatPriceCurrency === "xmrusd" ? appWindow.fiatPriceXMRUSD : appWindow.fiatPriceXMREUR;
var symbol = persistentSettings.fiatPriceCurrency === "xmrusd" ? "$" : "€"
if(ticker <= 0){ if(ticker <= 0){
console.log(fiatApiError("Could not update balance card; invalid ticker value")); console.log(fiatApiError("Could not update balance card; invalid ticker value"));
leftPanel.balanceFiatString = "?.??"; leftPanel.unlockedBalanceTextFiat = "N/A";
leftPanel.balanceTextFiat = "N/A";
return; return;
} }
var bFiat = "?.??"
if (!hideBalanceForced && !persistentSettings.hideBalance) { var uFiat = Utils.formatMoney(unlocked_balance * ticker);
bFiat = (balance * ticker).toFixed(2); var bFiat = Utils.formatMoney(balance * ticker);
}
leftPanel.balanceFiatString = bFiat; leftPanel.unlockedBalanceTextFiat = symbol + uFiat;
leftPanel.balanceTextFiat = symbol + bFiat;
} }
function fiatTimerStart(){ function fiatTimerStart(){
@@ -1271,11 +1287,9 @@ ApplicationWindow {
Component.onCompleted: { Component.onCompleted: {
x = (Screen.width - width) / 2 x = (Screen.width - width) / 2
y = (Screen.height - maxWindowHeight) / 2 y = (Screen.height - maxWindowHeight) / 2
applyWalletMode(persistentSettings.walletMode);
// //
walletManager.walletOpened.connect(onWalletOpened); walletManager.walletOpened.connect(onWalletOpened);
walletManager.walletClosed.connect(onWalletClosed);
walletManager.deviceButtonRequest.connect(onDeviceButtonRequest); walletManager.deviceButtonRequest.connect(onDeviceButtonRequest);
walletManager.deviceButtonPressed.connect(onDeviceButtonPressed); walletManager.deviceButtonPressed.connect(onDeviceButtonPressed);
walletManager.checkUpdatesComplete.connect(onWalletCheckUpdatesComplete); walletManager.checkUpdatesComplete.connect(onWalletCheckUpdatesComplete);
@@ -1327,14 +1341,8 @@ ApplicationWindow {
} }
} }
MoneroSettings { Settings {
id: persistentSettings id: persistentSettings
fileName: {
if(isTails && tailsUsePersistence)
return homePath + "/Persistent/Monero/monero-core.conf";
return "";
}
property string language property string language
property string locale property string locale
property string account_name property string account_name
@@ -1363,6 +1371,7 @@ ApplicationWindow {
property bool useRemoteNode: false property bool useRemoteNode: false
property string remoteNodeAddress: "" property string remoteNodeAddress: ""
property string bootstrapNodeAddress: "" property string bootstrapNodeAddress: ""
property string remoteNodeRegion: ""
property bool segregatePreForkOutputs: true property bool segregatePreForkOutputs: true
property bool keyReuseMitigation2: true property bool keyReuseMitigation2: true
property int segregationHeight: 0 property int segregationHeight: 0
@@ -1370,7 +1379,9 @@ ApplicationWindow {
property bool hideBalance: false property bool hideBalance: false
property bool lockOnUserInActivity: true property bool lockOnUserInActivity: true
property int walletMode: 2 property int walletMode: 2
property string remoteNodeService: ""
property int lockOnUserInActivityInterval: 10 // minutes property int lockOnUserInActivityInterval: 10 // minutes
property bool showPid: false
property bool blackTheme: true property bool blackTheme: true
property bool fiatPriceEnabled: false property bool fiatPriceEnabled: false
@@ -1483,15 +1494,13 @@ ApplicationWindow {
} }
} }
PasswordDialog { PassphraseDialog {
id: passwordDialog id: passphraseDialog
visible: false visible: false
z: parent.z + 1 z: parent.z + 1
anchors.fill: parent anchors.fill: parent
property var onAcceptedCallback property var onAcceptedCallback
property var onRejectedCallback property var onRejectedCallback
property var onAcceptedPassphraseCallback
property var onRejectedPassphraseCallback
onAccepted: { onAccepted: {
if (onAcceptedCallback) if (onAcceptedCallback)
onAcceptedCallback(); onAcceptedCallback();
@@ -1500,9 +1509,33 @@ ApplicationWindow {
if (onRejectedCallback) if (onRejectedCallback)
onRejectedCallback(); onRejectedCallback();
} }
onAcceptedNewPassword: { }
if (currentWallet.setPassword(passwordDialog.password)) {
appWindow.walletPassword = passwordDialog.password; PasswordDialog {
id: passwordDialog
visible: false
z: parent.z + 1
anchors.fill: parent
property var onAcceptedCallback
property var onRejectedCallback
onAccepted: {
if (onAcceptedCallback)
onAcceptedCallback();
}
onRejected: {
if (onRejectedCallback)
onRejectedCallback();
}
}
NewPasswordDialog {
id: newPasswordDialog
z: parent.z + 1
visible:false
anchors.fill: parent
onAccepted: {
if (currentWallet.setPassword(newPasswordDialog.password)) {
appWindow.walletPassword = newPasswordDialog.password;
informationPopup.title = qsTr("Information") + translationManager.emptyString; informationPopup.title = qsTr("Information") + translationManager.emptyString;
informationPopup.text = qsTr("Password changed successfully") + translationManager.emptyString; informationPopup.text = qsTr("Password changed successfully") + translationManager.emptyString;
informationPopup.icon = StandardIcon.Information; informationPopup.icon = StandardIcon.Information;
@@ -1514,14 +1547,7 @@ ApplicationWindow {
informationPopup.onCloseCallback = null; informationPopup.onCloseCallback = null;
informationPopup.open(); informationPopup.open();
} }
onRejectedNewPassword: {} onRejected: {
onAcceptedPassphrase: {
if (onAcceptedPassphraseCallback)
onAcceptedPassphraseCallback();
}
onRejectedPassphrase: {
if (onRejectedPassphraseCallback)
onRejectedPassphraseCallback();
} }
} }
@@ -1569,89 +1595,153 @@ ApplicationWindow {
states: [ states: [
State { State {
name: "wizard" name: "wizard"
PropertyChanges { target: leftPanel; visible: false }
PropertyChanges { target: middlePanel; visible: false } PropertyChanges { target: middlePanel; visible: false }
PropertyChanges { target: wizard; visible: true } PropertyChanges { target: wizard; visible: true }
PropertyChanges { target: resizeArea; visible: true } PropertyChanges { target: resizeArea; visible: true }
PropertyChanges { target: mobileHeader; visible: false }
PropertyChanges { target: titleBar; state: "essentials" } PropertyChanges { target: titleBar; state: "essentials" }
}, State { }, State {
name: "normal" name: "normal"
PropertyChanges { target: leftPanel; visible: (isMobile)? false : true }
PropertyChanges { target: middlePanel; visible: true } PropertyChanges { target: middlePanel; visible: true }
PropertyChanges { target: titleBar; basicButtonVisible: true }
PropertyChanges { target: wizard; visible: false } PropertyChanges { target: wizard; visible: false }
PropertyChanges { target: resizeArea; visible: true } PropertyChanges { target: resizeArea; visible: true }
PropertyChanges { target: titleBar; state: "default" } PropertyChanges { target: titleBar; state: "default" }
PropertyChanges { target: mobileHeader; visible: isMobile ? true : false }
} }
] ]
MobileHeader {
id: mobileHeader
visible: isMobile
anchors.left: parent.left
anchors.right: parent.right
height: visible? 65 : 0
MouseArea {
enabled: persistentSettings.customDecorations
property var previousPosition
anchors.fill: parent
propagateComposedEvents: true
onPressed: previousPosition = globalCursor.getPosition()
onPositionChanged: {
if (pressedButtons == Qt.LeftButton) {
var pos = globalCursor.getPosition()
var dx = pos.x - previousPosition.x
var dy = pos.y - previousPosition.y
appWindow.x += dx
appWindow.y += dy
previousPosition = pos
}
}
}
}
LeftPanel { LeftPanel {
id: leftPanel id: leftPanel
anchors.top: parent.top anchors.top: mobileHeader.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
visible: rootItem.state == "normal" && middlePanel.state != "Merchant"
onTransferClicked: { onTransferClicked: {
middlePanel.state = "Transfer"; middlePanel.state = "Transfer";
middlePanel.flickable.contentY = 0; middlePanel.flickable.contentY = 0;
if(isMobile) {
hideMenu();
}
updateBalance(); updateBalance();
} }
onReceiveClicked: { onReceiveClicked: {
middlePanel.state = "Receive"; middlePanel.state = "Receive";
middlePanel.flickable.contentY = 0; middlePanel.flickable.contentY = 0;
if(isMobile) {
hideMenu();
}
updateBalance(); updateBalance();
} }
onMerchantClicked: { onMerchantClicked: {
middlePanel.state = "Merchant"; middlePanel.state = "Merchant";
middlePanel.flickable.contentY = 0; middlePanel.flickable.contentY = 0;
if(isMobile) {
hideMenu();
}
updateBalance(); updateBalance();
} }
onTxkeyClicked: { onTxkeyClicked: {
middlePanel.state = "TxKey"; middlePanel.state = "TxKey";
middlePanel.flickable.contentY = 0; middlePanel.flickable.contentY = 0;
if(isMobile) {
hideMenu();
}
updateBalance(); updateBalance();
} }
onSharedringdbClicked: { onSharedringdbClicked: {
middlePanel.state = "SharedRingDB"; middlePanel.state = "SharedRingDB";
middlePanel.flickable.contentY = 0; middlePanel.flickable.contentY = 0;
if(isMobile) {
hideMenu();
}
updateBalance(); updateBalance();
} }
onHistoryClicked: { onHistoryClicked: {
middlePanel.state = "History"; middlePanel.state = "History";
middlePanel.flickable.contentY = 0; middlePanel.flickable.contentY = 0;
if(isMobile) {
hideMenu();
}
updateBalance(); updateBalance();
} }
onAddressBookClicked: { onAddressBookClicked: {
middlePanel.state = "AddressBook"; middlePanel.state = "AddressBook";
middlePanel.flickable.contentY = 0; middlePanel.flickable.contentY = 0;
if(isMobile) {
hideMenu();
}
updateBalance(); updateBalance();
} }
onMiningClicked: { onMiningClicked: {
middlePanel.state = "Mining"; middlePanel.state = "Mining";
middlePanel.flickable.contentY = 0; middlePanel.flickable.contentY = 0;
if(isMobile) {
hideMenu();
}
updateBalance(); updateBalance();
} }
onSignClicked: { onSignClicked: {
middlePanel.state = "Sign"; middlePanel.state = "Sign";
middlePanel.flickable.contentY = 0; middlePanel.flickable.contentY = 0;
if(isMobile) {
hideMenu();
}
updateBalance(); updateBalance();
} }
onSettingsClicked: { onSettingsClicked: {
middlePanel.state = "Settings"; middlePanel.state = "Settings";
middlePanel.flickable.contentY = 0; middlePanel.flickable.contentY = 0;
if(isMobile) {
hideMenu();
}
updateBalance(); updateBalance();
} }
onAccountClicked: { onAccountClicked: {
middlePanel.state = "Account"; middlePanel.state = "Account";
middlePanel.flickable.contentY = 0; middlePanel.flickable.contentY = 0;
if(isMobile) {
hideMenu();
}
updateBalance(); updateBalance();
} }
} }
@@ -1659,13 +1749,102 @@ ApplicationWindow {
MiddlePanel { MiddlePanel {
id: middlePanel id: middlePanel
anchors.top: parent.top anchors.top: mobileHeader.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.left: leftPanel.visible ? leftPanel.right : parent.left anchors.left: leftPanel.visible ? leftPanel.right : parent.left
anchors.right: parent.right anchors.right: parent.right
state: "Transfer" state: "Transfer"
} }
SequentialAnimation {
id: goToBasicAnimation
// PropertyAction {
// target: appWindow
// properties: "visibility"
// value: Window.Windowed
// }
// PropertyAction {
// target: titleBar
// properties: "maximizeButtonVisible"
// value: false
// }
// PropertyAction {
// target: frameArea
// properties: "blocked"
// value: true
// }
PropertyAction {
target: resizeArea
properties: "visible"
value: true
}
// PropertyAction {
// target: appWindow
// properties: "height"
// value: 30
// }
// PropertyAction {
// target: appWindow
// properties: "width"
// value: 326
// }
PropertyAction {
target: leftPanel
properties: "visible"
value: false
}
PropertyAction {
target: middlePanel
properties: "basicMode"
value: true
}
// PropertyAction {
// target: appWindow
// properties: "height"
// value: middlePanel.height
// }
onStopped: {
// middlePanel.visible = false
leftPanel.visible = false
}
}
SequentialAnimation {
id: goToProAnimation
// PropertyAction {
// target: appWindow
// properties: "height"
// value: 30
// }
PropertyAction {
target: middlePanel
properties: "basicMode"
value: false
}
PropertyAction {
targets: [leftPanel, middlePanel, resizeArea]
properties: "visible"
value: true
}
// PropertyAction {
// target: appWindow
// properties: "height"
// value: maxWindowHeight
// }
// PropertyAction {
// target: frameArea
// properties: "blocked"
// value: false
// }
// PropertyAction {
// target: titleBar
// properties: "maximizeButtonVisible"
// value: true
// }
}
WizardController { WizardController {
id: wizard id: wizard
anchors.fill: parent anchors.fill: parent
@@ -1730,14 +1909,21 @@ ApplicationWindow {
TitleBar { TitleBar {
id: titleBar id: titleBar
visible: persistentSettings.customDecorations && middlePanel.state !== "Merchant" visible: persistentSettings.customDecorations && middlePanel.state !== "Merchant"
walletName: appWindow.walletName
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
onCloseClicked: appWindow.close(); onCloseClicked: appWindow.close();
onLanguageClicked: appWindow.toggleLanguageView(); onLanguageClicked: appWindow.toggleLanguageView();
onCloseWalletClicked: appWindow.showWizard();
onMaximizeClicked: appWindow.visibility = appWindow.visibility !== Window.Maximized ? Window.Maximized : Window.Windowed onMaximizeClicked: appWindow.visibility = appWindow.visibility !== Window.Maximized ? Window.Maximized : Window.Windowed
onMinimizeClicked: appWindow.visibility = Window.Minimized onMinimizeClicked: appWindow.visibility = Window.Minimized
onGoToBasicVersion: {
if (yes) {
// basicPanel.currentView = middlePanel.currentView
goToBasicAnimation.start()
} else {
// middlePanel.currentView = basicPanel.currentView
goToProAnimation.start()
}
}
} }
MoneroMerchant.MerchantTitlebar { MoneroMerchant.MerchantTitlebar {
@@ -1821,43 +2007,41 @@ ApplicationWindow {
onTriggered: appWindow.themeTransition = true; onTriggered: appWindow.themeTransition = true;
} }
function checkNoSyncFlag() {
if (!appWindow.daemonRunning) {
return true;
}
if (appWindow.walletMode == 0 && !daemonManager.noSync()) {
return false;
}
if (appWindow.walletMode == 1 && daemonManager.noSync()) {
return false;
}
return true;
}
function checkSimpleModeConnection(){ function checkSimpleModeConnection(){
// auto-connection mechanism for simple mode // auto-connection mechanism for simple mode
if(persistentSettings.nettype != NetworkType.MAINNET) return;
if(appWindow.walletMode >= 2) return; if(appWindow.walletMode >= 2) return;
const disconnectedTimeoutSec = 30; var disconnected = leftPanel.networkStatus.connected === Wallet.ConnectionStatus_Disconnected;
const firstCheckDelaySec = 2; var disconnectedEpoch = appWindow.disconnectedEpoch;
if(disconnectedEpoch === 0){
const connected = leftPanel.networkStatus.connected !== Wallet.ConnectionStatus_Disconnected;
const firstRun = appWindow.disconnectedEpoch == 0;
if (firstRun) {
appWindow.disconnectedEpoch = Utils.epoch() + firstCheckDelaySec - disconnectedTimeoutSec;
} else if (connected) {
appWindow.disconnectedEpoch = Utils.epoch(); appWindow.disconnectedEpoch = Utils.epoch();
} }
const sinceLastConnect = Utils.epoch() - appWindow.disconnectedEpoch; // disconnected longer than 5 seconds?
if (sinceLastConnect < disconnectedTimeoutSec && checkNoSyncFlag()) { if(disconnected && disconnectedEpoch > 0 && (Utils.epoch() - disconnectedEpoch) >= 5){
return; // for bootstrap mode, first wait until daemon is killed
} if(appWindow.walletMode === 1 && appWindow.daemonRunning) {
appWindow.stopDaemon();
return;
}
if (appWindow.daemonRunning) { // fetch new node list
appWindow.stopDaemon(); wizard.fetchRemoteNodes(function() {
// fetched node, connect
if(appWindow.walletMode === 0){
appWindow.connectRemoteNode();
} else if(appWindow.walletMode === 1){
appWindow.startDaemon(persistentSettings.daemonFlags);
}
// reset state
appWindow.disconnectedEpoch = 0;
return;
}, function(){
appWindow.showStatusMessage(qsTr("Failed to fetch remote nodes from third-party server."), simpleModeConnectionTimer.interval / 1000);
});
} }
appWindow.startDaemon("");
} }
Timer { Timer {
@@ -1936,12 +2120,7 @@ ApplicationWindow {
closeAccepted(); closeAccepted();
}; };
if (appWindow.walletMode == 0) { confirmationDialog.open()
stopDaemon();
closeAccepted();
} else {
confirmationDialog.open();
}
} else { } else {
closeAccepted(); closeAccepted();
@@ -1952,8 +2131,8 @@ ApplicationWindow {
console.log("close accepted"); console.log("close accepted");
// Close wallet non async on exit // Close wallet non async on exit
daemonManager.exit(); daemonManager.exit();
walletManager.closeWallet();
closeWallet(Qt.quit); Qt.quit();
} }
function onWalletCheckUpdatesComplete(update) { function onWalletCheckUpdatesComplete(update) {
@@ -2003,8 +2182,8 @@ ApplicationWindow {
// reset label text. othewise potential privacy leak showing unlock time when switching wallets // reset label text. othewise potential privacy leak showing unlock time when switching wallets
function clearMoneroCardLabelText(){ function clearMoneroCardLabelText(){
leftPanel.balanceString = "?.??" leftPanel.minutesToUnlockTxt = qsTr("Unlocked balance")
leftPanel.balanceFiatString = "?.??" leftPanel.balanceLabelText = qsTr("Balance")
} }
// some fields need an extra nudge when changing languages // some fields need an extra nudge when changing languages
@@ -2022,7 +2201,6 @@ ApplicationWindow {
function checkInUserActivity() { function checkInUserActivity() {
if(rootItem.state !== "normal") return; if(rootItem.state !== "normal") return;
if(!persistentSettings.lockOnUserInActivity) return; if(!persistentSettings.lockOnUserInActivity) return;
if(passwordDialog.visible) return;
// prompt password after X seconds of inactivity // prompt password after X seconds of inactivity
var epoch = Math.floor((new Date).getTime() / 1000); var epoch = Math.floor((new Date).getTime() / 1000);
@@ -2053,22 +2231,11 @@ ApplicationWindow {
} }
function changeWalletMode(mode){ function changeWalletMode(mode){
appWindow.disconnectedEpoch = 0;
appWindow.walletMode = mode; appWindow.walletMode = mode;
persistentSettings.walletMode = mode; persistentSettings.walletMode = mode;
applyWalletMode(mode); persistentSettings.useRemoteNode = mode === 0 ? true : false;
}
function applyWalletMode(mode){ console.log("walletMode changed: " + (mode === 0 ? "simple": mode === 1 ? "simple (bootstrap)" : "Advanced"));
if (mode < 2) {
persistentSettings.useRemoteNode = false;
persistentSettings.bootstrapNodeAddress = "auto";
if (middlePanel.settingsView.settingsStateViewState === "Node" || middlePanel.settingsView.settingsStateViewState === "Log") {
middlePanel.settingsView.settingsStateViewState = "Wallet"
}
}
console.log("walletMode: " + (mode === 0 ? "simple": mode === 1 ? "simple (bootstrap)" : "Advanced"));
} }
// Daemon console // Daemon console

View File

@@ -1,6 +1,6 @@
# qml components require at least QT 5.9.7 # qml components require at least QT 5.7.0
lessThan (QT_MAJOR_VERSION, 5) | lessThan (QT_MINOR_VERSION, 9) { lessThan (QT_MAJOR_VERSION, 5) | lessThan (QT_MINOR_VERSION, 7) {
error("Can't build with Qt $${QT_VERSION}. Use at least Qt 5.9.7") error("Can't build with Qt $${QT_VERSION}. Use at least Qt 5.7.0")
} }
TEMPLATE = app TEMPLATE = app
@@ -16,21 +16,10 @@ packagesExist(libusb-1.0) {
packagesExist(hidapi-libusb) { packagesExist(hidapi-libusb) {
PKGCONFIG += hidapi-libusb PKGCONFIG += hidapi-libusb
} }
!win32 {
GCC_VERSION = $$system("g++ -dumpversion")
GCC_VERSION = $$split(GCC_VERSION, .)
GCC_VERSION_MAJOR = $$member(GCC_VERSION, 0)
GCC_VERSION_MINOR = $$member(GCC_VERSION, 1)
greaterThan(GCC_VERSION_MAJOR, 9) | if(equals(GCC_VERSION_MAJOR, 9) : greaterThan(GCC_VERSION_MINOR, 0)) {
GCC_9_1_OR_GREATER = TRUE
}
!win32 | !isEmpty(GCC_9_1_OR_GREATER) {
QMAKE_CXXFLAGS += -fPIC -fstack-protector -fstack-protector-strong QMAKE_CXXFLAGS += -fPIC -fstack-protector -fstack-protector-strong
QMAKE_LFLAGS += -fstack-protector -fstack-protector-strong QMAKE_LFLAGS += -fstack-protector -fstack-protector-strong
}
!win32 {
packagesExist(protobuf) { packagesExist(protobuf) {
PKGCONFIG += protobuf PKGCONFIG += protobuf
} }
@@ -76,12 +65,10 @@ HEADERS += \
MainApp.h \ MainApp.h \
src/qt/FutureScheduler.h \ src/qt/FutureScheduler.h \
src/qt/ipc.h \ src/qt/ipc.h \
src/qt/mime.h \
src/qt/KeysFiles.h \ src/qt/KeysFiles.h \
src/qt/utils.h \ src/qt/utils.h \
src/qt/prices.h \ src/qt/prices.h
src/qt/macoshelper.h \
src/qt/MoneroSettings.h \
src/qt/TailsOS.h
SOURCES += main.cpp \ SOURCES += main.cpp \
filter.cpp \ filter.cpp \
@@ -112,11 +99,10 @@ SOURCES += main.cpp \
MainApp.cpp \ MainApp.cpp \
src/qt/FutureScheduler.cpp \ src/qt/FutureScheduler.cpp \
src/qt/ipc.cpp \ src/qt/ipc.cpp \
src/qt/mime.cpp \
src/qt/KeysFiles.cpp \ src/qt/KeysFiles.cpp \
src/qt/utils.cpp \ src/qt/utils.cpp \
src/qt/prices.cpp \ src/qt/prices.cpp
src/qt/MoneroSettings.cpp \
src/qt/TailsOS.cpp
CONFIG(DISABLE_PASS_STRENGTH_METER) { CONFIG(DISABLE_PASS_STRENGTH_METER) {
HEADERS -= src/zxcvbn-c/zxcvbn.h HEADERS -= src/zxcvbn-c/zxcvbn.h
@@ -153,25 +139,25 @@ ios:arm64 {
LIBS += \ LIBS += \
-L$$PWD/../ofxiOSBoost/build/libs/boost/lib/arm64 \ -L$$PWD/../ofxiOSBoost/build/libs/boost/lib/arm64 \
} }
LIBS_COMMON = \
-lwallet_merged \
-llmdb \
-lepee \
-lunbound \
-lsodium \
-leasylogging \
-lrandomx
!ios:!android { !ios:!android {
LIBS += -L$$WALLET_ROOT/lib \ LIBS += -L$$WALLET_ROOT/lib \
$$LIBS_COMMON -lwallet_merged \
-llmdb \
-lepee \
-lunbound \
-lsodium \
-leasylogging
} }
android { android {
message("Host is Android") message("Host is Android")
LIBS += -L$$WALLET_ROOT/lib \ LIBS += -L$$WALLET_ROOT/lib \
$$LIBS_COMMON -lwallet_merged \
-llmdb \
-lepee \
-lunbound \
-lsodium \
-leasylogging
} }
@@ -186,7 +172,12 @@ ios {
QMAKE_IOS_DEVICE_ARCHS = arm64 QMAKE_IOS_DEVICE_ARCHS = arm64
CONFIG += arm64 CONFIG += arm64
LIBS += -L$$WALLET_ROOT/lib-ios \ LIBS += -L$$WALLET_ROOT/lib-ios \
$$LIBS_COMMON -lwallet_merged \
-llmdb \
-lepee \
-lunbound \
-lsodium \
-leasylogging
LIBS+= \ LIBS+= \
-L$$PWD/../OpenSSL-for-iPhone/lib \ -L$$PWD/../OpenSSL-for-iPhone/lib \
@@ -293,7 +284,6 @@ win32 {
-licudt \ -licudt \
-licutu \ -licutu \
-liconv \ -liconv \
-lstdc++ \
-lpthread \ -lpthread \
-lsetupapi \ -lsetupapi \
-lssl \ -lssl \
@@ -349,8 +339,7 @@ linux {
if(!android) { if(!android) {
LIBS+= \ LIBS+= \
-Wl,-Bdynamic \ -Wl,-Bdynamic \
-lGL \ -lGL
-lX11
} }
# currently monero has an issue with "static" build and linunwind-dev, # currently monero has an issue with "static" build and linunwind-dev,
# so we link libunwind-dev only for non-Ubuntu distros # so we link libunwind-dev only for non-Ubuntu distros
@@ -370,8 +359,6 @@ macx {
# message("using static libraries") # message("using static libraries")
# LIBS+= -Wl,-Bstatic # LIBS+= -Wl,-Bstatic
# } # }
QT += macextras
OBJECTIVE_SOURCES += src/qt/macoshelper.mm
LIBS+= \ LIBS+= \
-L/usr/local/lib \ -L/usr/local/lib \
-L/usr/local/opt/openssl/lib \ -L/usr/local/opt/openssl/lib \
@@ -385,7 +372,6 @@ macx {
-lboost_chrono \ -lboost_chrono \
-lboost_program_options \ -lboost_program_options \
-framework CoreFoundation \ -framework CoreFoundation \
-framework AppKit \
-lhidapi \ -lhidapi \
-lssl \ -lssl \
-lsodium \ -lsodium \

View File

@@ -31,20 +31,6 @@
#include <QDir> #include <QDir>
#include <QDebug> #include <QDebug>
#include <QString> #include <QString>
#ifdef Q_OS_MAC
#include "qt/macoshelper.h"
#endif
#ifdef Q_OS_WIN32
#include <windows.h>
#endif
#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
#include <X11/XKBlib.h>
#undef KeyPress
#undef KeyRelease
#undef FocusIn
#undef FocusOut
// #undef those Xlib #defines that conflict with QEvent::Type enum
#endif
OSHelper::OSHelper(QObject *parent) : QObject(parent) OSHelper::OSHelper(QObject *parent) : QObject(parent)
{ {
@@ -72,27 +58,6 @@ bool OSHelper::removeTemporaryWallet(const QString &fileName) const
return cache_deleted && address_deleted && keys_deleted; return cache_deleted && address_deleted && keys_deleted;
} }
// https://stackoverflow.com/a/3006934
bool OSHelper::isCapsLock() const
{
// platform dependent method of determining if CAPS LOCK is on
#if defined(Q_OS_WIN32) // MS Windows version
return GetKeyState(VK_CAPITAL) == 1;
#elif defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) // X11 version
Display * d = XOpenDisplay((char*)0);
bool caps_state = false;
if (d) {
unsigned n;
XkbGetIndicatorState(d, XkbUseCoreKbd, &n);
caps_state = (n & 0x01) == 1;
}
return caps_state;
#elif defined(Q_OS_MAC)
return MacOSHelper::isCapsLock();
#endif
return false;
}
QString OSHelper::temporaryPath() const QString OSHelper::temporaryPath() const
{ {
return QDir::tempPath(); return QDir::tempPath();

View File

@@ -42,7 +42,6 @@ public:
Q_INVOKABLE QString temporaryFilename() const; Q_INVOKABLE QString temporaryFilename() const;
Q_INVOKABLE QString temporaryPath() const; Q_INVOKABLE QString temporaryPath() const;
Q_INVOKABLE bool removeTemporaryWallet(const QString &walletName) const; Q_INVOKABLE bool removeTemporaryWallet(const QString &walletName) const;
Q_INVOKABLE bool isCapsLock() const;
signals: signals:

View File

@@ -64,7 +64,7 @@ Rectangle {
/* main layout */ /* main layout */
ColumnLayout { ColumnLayout {
id: mainLayout id: mainLayout
anchors.margins: 20 anchors.margins: (isMobile)? 17 : 20
anchors.topMargin: 40 anchors.topMargin: 40
anchors.left: parent.left anchors.left: parent.left
@@ -101,7 +101,8 @@ Rectangle {
id: balanceAll id: balanceAll
font.family: MoneroComponents.Style.fontMonoRegular.name; font.family: MoneroComponents.Style.fontMonoRegular.name;
font.pixelSize: 16 font.pixelSize: 16
color: MoneroComponents.Style.defaultFontColor color: MoneroComponents.Style.dimmedFontColor
themeTransition: false
MouseArea { MouseArea {
hoverEnabled: true hoverEnabled: true
@@ -134,7 +135,8 @@ Rectangle {
id: unlockedBalanceAll id: unlockedBalanceAll
font.family: MoneroComponents.Style.fontMonoRegular.name; font.family: MoneroComponents.Style.fontMonoRegular.name;
font.pixelSize: 16 font.pixelSize: 16
color: MoneroComponents.Style.defaultFontColor color: MoneroComponents.Style.dimmedFontColor
themeTransition: false
MouseArea { MouseArea {
hoverEnabled: true hoverEnabled: true
@@ -175,7 +177,7 @@ Rectangle {
ListView { ListView {
id: subaddressAccountListView id: subaddressAccountListView
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true anchors.fill: parent
clip: true clip: true
boundsBehavior: ListView.StopAtBounds boundsBehavior: ListView.StopAtBounds
interactive: false interactive: false
@@ -363,7 +365,6 @@ Rectangle {
appWindow.currentWallet.subaddressAccount.addRow(inputDialog.inputText) appWindow.currentWallet.subaddressAccount.addRow(inputDialog.inputText)
appWindow.currentWallet.switchSubaddressAccount(appWindow.currentWallet.numSubaddressAccounts() - 1) appWindow.currentWallet.switchSubaddressAccount(appWindow.currentWallet.numSubaddressAccounts() - 1)
current_subaddress_account_table_index = appWindow.currentWallet.numSubaddressAccounts() - 1 current_subaddress_account_table_index = appWindow.currentWallet.numSubaddressAccounts() - 1
subaddressAccountListView.currentIndex = current_subaddress_account_table_index
appWindow.onWalletUpdate(); appWindow.onWalletUpdate();
} }
inputDialog.onRejectedCallback = null; inputDialog.onRejectedCallback = null;

View File

@@ -52,7 +52,7 @@ Rectangle {
ColumnLayout { ColumnLayout {
id: mainLayout id: mainLayout
anchors.margins: 20 anchors.margins: (isMobile)? 17 : 20
anchors.topMargin: 40 anchors.topMargin: 40
anchors.left: parent.left anchors.left: parent.left
@@ -145,7 +145,7 @@ Rectangle {
ListView { ListView {
id: addressBookListView id: addressBookListView
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true anchors.fill: parent
clip: true clip: true
boundsBehavior: ListView.StopAtBounds boundsBehavior: ListView.StopAtBounds
interactive: false interactive: false

View File

@@ -49,9 +49,9 @@ Rectangle {
property var model property var model
property int sideMargin: 50 property int sideMargin: 50
property var initialized: false property var initialized: false
property int txMax: Math.max(5, ((appWindow.height - 250) / 60)) property int txMax: 5
property int txOffset: 0 property int txOffset: 0
property int txPage: (txOffset / txMax) + 1 property int txPage: (txOffset / 5) + 1
property int txCount: 0 property int txCount: 0
property var sortSearchString: null property var sortSearchString: null
property bool sortDirection: true // true = desc, false = asc property bool sortDirection: true // true = desc, false = asc
@@ -67,8 +67,6 @@ Rectangle {
color: "transparent" color: "transparent"
onTxMaxChanged: root.updateDisplay(root.txOffset, root.txMax);
ColumnLayout { ColumnLayout {
id: pageRoot id: pageRoot
anchors.topMargin: 40 anchors.topMargin: 40
@@ -251,6 +249,7 @@ Rectangle {
font.pixelSize: 15 font.pixelSize: 15
text: qsTr("Blockheight") + translationManager.emptyString text: qsTr("Blockheight") + translationManager.emptyString
color: root.sortBy === "blockheight" ? MoneroComponents.Style.defaultFontColor : MoneroComponents.Style.dimmedFontColor color: root.sortBy === "blockheight" ? MoneroComponents.Style.defaultFontColor : MoneroComponents.Style.dimmedFontColor
anchors.verticalCenter: parent.verticalCenter
themeTransition: false themeTransition: false
} }
@@ -311,6 +310,7 @@ Rectangle {
text: qsTr("Date") + translationManager.emptyString text: qsTr("Date") + translationManager.emptyString
color: root.sortBy === "timestamp" ? MoneroComponents.Style.defaultFontColor : MoneroComponents.Style.dimmedFontColor color: root.sortBy === "timestamp" ? MoneroComponents.Style.defaultFontColor : MoneroComponents.Style.dimmedFontColor
themeTransition: false themeTransition: false
anchors.verticalCenter: parent.verticalCenter
} }
MoneroEffects.ImageMask { MoneroEffects.ImageMask {
@@ -370,6 +370,7 @@ Rectangle {
text: qsTr("Amount") + translationManager.emptyString text: qsTr("Amount") + translationManager.emptyString
color: root.sortBy === "amount" ? MoneroComponents.Style.defaultFontColor : MoneroComponents.Style.dimmedFontColor color: root.sortBy === "amount" ? MoneroComponents.Style.defaultFontColor : MoneroComponents.Style.dimmedFontColor
themeTransition: false themeTransition: false
anchors.verticalCenter: parent.verticalCenter
} }
MoneroEffects.ImageMask { MoneroEffects.ImageMask {
@@ -939,7 +940,7 @@ Rectangle {
anchors.leftMargin: 10 anchors.leftMargin: 10
text: FontAwesome.productHunt text: FontAwesome.productHunt
small: true small: true
label.font.family: FontAwesome.fontFamilyBrands label.font.family: FontAwesome.fontFamily
fontSize: 18 fontSize: 18
width: 36 width: 36
@@ -1342,14 +1343,13 @@ Rectangle {
root.updateDisplay(root.txOffset, root.txMax); root.updateDisplay(root.txOffset, root.txMax);
} }
function reset(keepDate) { function reset() {
root.txOffset = 0; root.txOffset = 0;
root.txMax = 5;
if (typeof root.model !== 'undefined' && root.model != null) { if (typeof root.model !== 'undefined' && root.model != null) {
if (!keepDate) { root.model.dateFromFilter = "2014-04-18" // genesis block
root.model.dateFromFilter = "2014-04-18" // genesis block root.model.dateToFilter = "9999-09-09" // fix before september 9999
root.model.dateToFilter = "9999-09-09" // fix before september 9999
}
// negative values disable filters here; // negative values disable filters here;
root.model.amountFromFilter = -1; root.model.amountFromFilter = -1;
root.model.amountToFilter = -1; root.model.amountToFilter = -1;
@@ -1361,9 +1361,8 @@ Rectangle {
// applying filters // applying filters
root.txData = JSON.parse(JSON.stringify(root.txModelData)); // deepcopy root.txData = JSON.parse(JSON.stringify(root.txModelData)); // deepcopy
const timezoneOffset = new Date().getTimezoneOffset() * 60; var fromDate = fromDatePicker.currentDate.getTime() / 1000;
var fromDate = Math.floor(fromDatePicker.currentDate.getTime() / 86400000) * 86400 + timezoneOffset; var toDate = toDatePicker.currentDate.getTime() / 1000;
var toDate = (Math.floor(toDatePicker.currentDate.getTime() / 86400000) + 1) * 86400 + timezoneOffset;
var txs = []; var txs = [];
for (var i = 0; i < root.txData.length; i++){ for (var i = 0; i < root.txData.length; i++){
@@ -1388,8 +1387,6 @@ Rectangle {
txs.push(item); txs.push(item);
} else if(item.blockheight.toString().startsWith(root.sortSearchString)) { } else if(item.blockheight.toString().startsWith(root.sortSearchString)) {
txs.push(item); txs.push(item);
} else if(item.tx_note.toLowerCase().indexOf(root.sortSearchString.toLowerCase()) !== -1) {
txs.push(item);
} else if (item.hash.startsWith(root.sortSearchString)){ } else if (item.hash.startsWith(root.sortSearchString)){
txs.push(item); txs.push(item);
} }
@@ -1583,9 +1580,9 @@ Rectangle {
elem.parent.text = txKey ? txKey : '-'; elem.parent.text = txKey ? txKey : '-';
elem.parent.state = 'ready'; elem.parent.state = 'ready';
}); });
} else {
toClipboard(elem.parent.text);
} }
toClipboard(elem.parent.text);
} }
function showTxDetails(hash, paymentId, destinations, subaddrAccount, subaddrIndex){ function showTxDetails(hash, paymentId, destinations, subaddrAccount, subaddrIndex){
@@ -1707,6 +1704,6 @@ Rectangle {
function onPageClosed(){ function onPageClosed(){
root.initialized = false; root.initialized = false;
root.reset(true); root.reset();
} }
} }

View File

@@ -52,7 +52,7 @@ Rectangle {
anchors.top: parent.top anchors.top: parent.top
anchors.right: parent.right anchors.right: parent.right
anchors.margins: 20 anchors.margins: (isMobile)? 17 : 20
anchors.topMargin: 40 anchors.topMargin: 40
spacing: 30 spacing: 30
@@ -116,11 +116,11 @@ Rectangle {
MoneroComponents.LineEdit { MoneroComponents.LineEdit {
Layout.fillWidth: true Layout.fillWidth: true
id: walletCreationHeight
readOnly: true readOnly: true
copyButton: true copyButton: true
labelText: qsTr("Block #") + translationManager.emptyString labelText: qsTr("Block #") + translationManager.emptyString
fontSize: 16 fontSize: 16
text: currentWallet.walletCreationHeight
} }
} }
@@ -251,7 +251,7 @@ Rectangle {
onClicked: { onClicked: {
loadPage("Settings") loadPage("Settings")
} }
Layout.alignment: Qt.AlignCenter anchors.horizontalCenter: parent.horizontalCenter
width: 135 width: 135
} }
} }
@@ -261,7 +261,6 @@ Rectangle {
function onPageCompleted() { function onPageCompleted() {
console.log("keys page loaded"); console.log("keys page loaded");
walletCreationHeight.text = currentWallet.walletCreationHeight
secretViewKey.text = currentWallet.secretViewKey secretViewKey.text = currentWallet.secretViewKey
publicViewKey.text = currentWallet.publicViewKey publicViewKey.text = currentWallet.publicViewKey
secretSpendKey.text = (!currentWallet.viewOnly) ? currentWallet.secretSpendKey : "" secretSpendKey.text = (!currentWallet.viewOnly) ? currentWallet.secretSpendKey : ""

View File

@@ -41,7 +41,7 @@ Rectangle {
ColumnLayout { ColumnLayout {
id: mainLayout id: mainLayout
Layout.fillWidth: true Layout.fillWidth: true
anchors.margins: 20 anchors.margins: (isMobile)? 17 : 20
anchors.topMargin: 40 anchors.topMargin: 40
anchors.left: parent.left anchors.left: parent.left
anchors.top: parent.top anchors.top: parent.top

View File

@@ -31,7 +31,6 @@ import QtQuick.Controls 2.0
import QtQuick.Controls.Styles 1.4 import QtQuick.Controls.Styles 1.4
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.1
import QtQuick.Dialogs 1.2 import QtQuick.Dialogs 1.2
import FontAwesome 1.0
import "../components" as MoneroComponents import "../components" as MoneroComponents
import "../components/effects/" as MoneroEffects import "../components/effects/" as MoneroEffects
@@ -66,7 +65,7 @@ Rectangle {
/* main layout */ /* main layout */
ColumnLayout { ColumnLayout {
id: mainLayout id: mainLayout
anchors.margins: 20 anchors.margins: (isMobile)? 17 : 20
anchors.topMargin: 40 anchors.topMargin: 40
anchors.left: parent.left anchors.left: parent.left
@@ -102,7 +101,7 @@ Rectangle {
ListView { ListView {
id: subaddressListView id: subaddressListView
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true anchors.fill: parent
clip: true clip: true
boundsBehavior: ListView.StopAtBounds boundsBehavior: ListView.StopAtBounds
interactive: false interactive: false
@@ -257,7 +256,6 @@ Rectangle {
inputDialog.onAcceptedCallback = function() { inputDialog.onAcceptedCallback = function() {
appWindow.currentWallet.subaddress.addRow(appWindow.currentWallet.currentSubaddressAccount, inputDialog.inputText) appWindow.currentWallet.subaddress.addRow(appWindow.currentWallet.currentSubaddressAccount, inputDialog.inputText)
current_subaddress_table_index = appWindow.currentWallet.numSubaddresses(appWindow.currentWallet.currentSubaddressAccount) - 1 current_subaddress_table_index = appWindow.currentWallet.numSubaddresses(appWindow.currentWallet.currentSubaddressAccount) - 1
subaddressListView.currentIndex = current_subaddress_table_index
} }
inputDialog.onRejectedCallback = null; inputDialog.onRejectedCallback = null;
inputDialog.open() inputDialog.open()
@@ -310,20 +308,6 @@ Rectangle {
appWindow.showStatusMessage(qsTr("Copied to clipboard") + translationManager.emptyString, 3); appWindow.showStatusMessage(qsTr("Copied to clipboard") + translationManager.emptyString, 3);
} }
} }
MoneroComponents.StandardButton {
text: FontAwesome.eye
label.font.family: FontAwesome.fontFamily
fontSize: 24
width: 36
visible: appWindow.currentWallet ? appWindow.currentWallet.isHwBacked() : false
onClicked: {
appWindow.currentWallet.deviceShowAddressAsync(
appWindow.currentWallet.currentSubaddressAccount,
appWindow.current_subaddress_table_index,
'');
}
}
} }
} }

View File

@@ -80,7 +80,7 @@ Rectangle {
ColumnLayout { ColumnLayout {
id: mainLayout id: mainLayout
Layout.fillWidth: true Layout.fillWidth: true
anchors.margins: 20 anchors.margins: (isMobile)? 17 : 20
anchors.topMargin: 40 anchors.topMargin: 40
anchors.left: parent.left anchors.left: parent.left
@@ -296,7 +296,7 @@ Rectangle {
GridLayout{ GridLayout{
Layout.topMargin: 12 Layout.topMargin: 12
columns: 2 columns: (isMobile) ? 1 : 2
columnSpacing: 32 columnSpacing: 32
ColumnLayout { ColumnLayout {
@@ -368,7 +368,7 @@ Rectangle {
GridLayout { GridLayout {
columnSpacing: 20 columnSpacing: 20
columns: 2 columns: (isMobile) ? 1 : 2
MoneroComponents.CheckBox { MoneroComponents.CheckBox {
id: segregatePreForkOutputs id: segregatePreForkOutputs
@@ -405,7 +405,7 @@ Rectangle {
id: segregationHeightRow id: segregationHeightRow
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 17 Layout.topMargin: 17
columns: 2 columns: (isMobile) ? 1 : 2
columnSpacing: 32 columnSpacing: 32
MoneroComponents.LineEdit { MoneroComponents.LineEdit {

View File

@@ -88,7 +88,7 @@ Rectangle {
ColumnLayout { ColumnLayout {
id: mainLayout id: mainLayout
Layout.fillWidth: true Layout.fillWidth: true
anchors.margins: 20 anchors.margins: (isMobile)? 17 : 20
anchors.topMargin: 40 anchors.topMargin: 40
anchors.left: parent.left anchors.left: parent.left

View File

@@ -56,7 +56,7 @@ Rectangle {
property bool showAdvanced: false property bool showAdvanced: false
// @TODO: remove after pid removal hardfork // @TODO: remove after pid removal hardfork
property bool warningLongPidTransfer: false property bool warningLongPidTransfer: false
property bool warningLongPidDescription: descriptionLine.text.match(/^[0-9a-f]{64}$/i) property bool warningLongPidDescription: false
Clipboard { id: clipboard } Clipboard { id: clipboard }
@@ -123,7 +123,7 @@ Rectangle {
ColumnLayout { ColumnLayout {
id: pageRoot id: pageRoot
anchors.margins: 20 anchors.margins: (isMobile)? 17 : 20
anchors.topMargin: 40 anchors.topMargin: 40
anchors.left: parent.left anchors.left: parent.left
@@ -143,16 +143,8 @@ Rectangle {
} }
} }
RowLayout {
visible: leftPanel.minutesToUnlock !== ""
MoneroComponents.WarningBox {
text: qsTr("Spendable funds: %1 XMR. Please wait ~%2 minutes for your whole balance to become spendable.").arg(leftPanel.balanceUnlockedString).arg(leftPanel.minutesToUnlock)
}
}
GridLayout { GridLayout {
columns: appWindow.walletMode < 2 ? 1 : 2 columns: (isMobile || !(appWindow.walletMode >= 2)) ? 1 : 2
Layout.fillWidth: true Layout.fillWidth: true
columnSpacing: 32 columnSpacing: 32
@@ -211,10 +203,10 @@ Rectangle {
id: priorityModelV5 id: priorityModelV5
ListElement { column1: qsTr("Automatic") ; column2: ""; priority: 0} ListElement { column1: qsTr("Automatic") ; column2: ""; priority: 0}
ListElement { column1: qsTr("Slow (x0.2 fee)") ; column2: ""; priority: 1} ListElement { column1: qsTr("Slow (x0.25 fee)") ; column2: ""; priority: 1}
ListElement { column1: qsTr("Normal (x1 fee)") ; column2: ""; priority: 2 } ListElement { column1: qsTr("Normal (x1 fee)") ; column2: ""; priority: 2 }
ListElement { column1: qsTr("Fast (x5 fee)") ; column2: ""; priority: 3 } ListElement { column1: qsTr("Fast (x5 fee)") ; column2: ""; priority: 3 }
ListElement { column1: qsTr("Fastest (x200 fee)") ; column2: ""; priority: 4 } ListElement { column1: qsTr("Fastest (x41.5 fee)") ; column2: ""; priority: 4 }
} }
StandardDropdown { StandardDropdown {
@@ -269,7 +261,8 @@ Rectangle {
} }
} }
onTextChanged: { onTextChanged: {
warningLongPidTransfer = isLongPidService(text); // @TODO: remove after pid removal hardfork
warningLongPidTransfer = !persistentSettings.showPid && isLongPidService(text)
} }
inlineButton.text: FontAwesome.qrcode inlineButton.text: FontAwesome.qrcode
inlineButton.fontPixelSize: 22 inlineButton.fontPixelSize: 22
@@ -330,12 +323,6 @@ Rectangle {
} }
} }
MoneroComponents.WarningBox {
text: qsTr("Description field contents match long payment ID format. \
Please don't paste long payment ID into description field, your funds might be lost.") + translationManager.emptyString;
visible: warningLongPidDescription
}
ColumnLayout { ColumnLayout {
spacing: 15 spacing: 15
@@ -365,7 +352,7 @@ Rectangle {
} }
ColumnLayout { ColumnLayout {
visible: paymentIdCheckbox.checked visible: appWindow.persistentSettings.showPid || paymentIdCheckbox.checked
// @TODO: remove after pid removal hardfork // @TODO: remove after pid removal hardfork
CheckBox { CheckBox {
id: paymentIdCheckbox id: paymentIdCheckbox
@@ -388,7 +375,6 @@ Rectangle {
id: paymentIdLine id: paymentIdLine
fontBold: true fontBold: true
placeholderText: qsTr("64 hexadecimal characters") + translationManager.emptyString placeholderText: qsTr("64 hexadecimal characters") + translationManager.emptyString
readOnly: true
Layout.fillWidth: true Layout.fillWidth: true
wrapMode: Text.WrapAnywhere wrapMode: Text.WrapAnywhere
addressValidation: false addressValidation: false
@@ -400,10 +386,8 @@ Rectangle {
MoneroComponents.WarningBox { MoneroComponents.WarningBox {
// @TODO: remove after pid removal hardfork // @TODO: remove after pid removal hardfork
id: paymentIdWarningBox id: paymentIdWarningBox
text: qsTr("Long payment IDs are obsolete. \ text: qsTr("You can enable transfers with payment ID on the settings page.") + translationManager.emptyString;
Long payment IDs were not encrypted on the blockchain and would harm your privacy. \ visible: !persistentSettings.showPid && (warningLongPidTransfer || warningLongPidDescription)
If the party you're sending to still requires a long payment ID, please notify them.") + translationManager.emptyString;
visible: warningLongPidTransfer || paymentIdCheckbox.checked
} }
MoneroComponents.WarningBox { MoneroComponents.WarningBox {
@@ -459,7 +443,7 @@ Rectangle {
anchors.top: pageRoot.bottom anchors.top: pageRoot.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.margins: 20 anchors.margins: (isMobile)? 17 : 20
anchors.topMargin: 32 anchors.topMargin: 32
spacing: 26 spacing: 26
enabled: !viewOnly || pageRoot.enabled enabled: !viewOnly || pageRoot.enabled
@@ -478,7 +462,7 @@ Rectangle {
GridLayout { GridLayout {
visible: persistentSettings.transferShowAdvanced && appWindow.walletMode >= 2 visible: persistentSettings.transferShowAdvanced && appWindow.walletMode >= 2
columns: 6 columns: (isMobile) ? 2 : 6
StandardButton { StandardButton {
id: sweepUnmixableButton id: sweepUnmixableButton
@@ -777,11 +761,6 @@ Rectangle {
root.sendButtonWarning = qsTr("Transaction information is incorrect.") + translationManager.emptyString; root.sendButtonWarning = qsTr("Transaction information is incorrect.") + translationManager.emptyString;
return false; return false;
} }
if (paymentIdWarningBox.visible) {
return false;
}
return true; return true;
} }
} }

View File

@@ -45,7 +45,7 @@ Rectangle {
/* main layout */ /* main layout */
ColumnLayout { ColumnLayout {
id: mainLayout id: mainLayout
anchors.margins: 20 anchors.margins: (isMobile)? 17 : 20
anchors.topMargin: 40 anchors.topMargin: 40
anchors.left: parent.left anchors.left: parent.left
anchors.top: parent.top anchors.top: parent.top

View File

@@ -33,6 +33,8 @@ Item {
property var hiddenAmounts: [] property var hiddenAmounts: []
function onPageCompleted() { function onPageCompleted() {
appWindow.hideMenu();
// prepare tracking // prepare tracking
trackingCheckbox.checked = root.enableTracking trackingCheckbox.checked = root.enableTracking
root.update(); root.update();
@@ -54,6 +56,8 @@ Item {
timer.running = false timer.running = false
root.enableTracking = false root.enableTracking = false
trackingModel.clear() trackingModel.clear()
appWindow.showMenu();
} }
Image { Image {
@@ -89,8 +93,9 @@ Item {
anchors.right: parent.right anchors.right: parent.right
Item { Item {
Layout.preferredHeight: 220 height: 220
Layout.fillWidth: true anchors.left: parent.left
anchors.right: parent.right
Rectangle { Rectangle {
id: tracker id: tracker
@@ -253,7 +258,8 @@ Item {
Item { Item {
Layout.preferredHeight: 40 Layout.preferredHeight: 40
Layout.fillWidth: true anchors.left: parent.left
anchors.right: parent.right
Item { Item {
width: (parent.width - qrImg.width) - (50) width: (parent.width - qrImg.width) - (50)
@@ -518,7 +524,8 @@ Item {
Item { Item {
Layout.topMargin: 32 Layout.topMargin: 32
Layout.preferredHeight: 40 Layout.preferredHeight: 40
Layout.fillWidth: true anchors.left: parent.left
anchors.right: parent.right
ColumnLayout { ColumnLayout {
spacing: 16 spacing: 16
@@ -623,7 +630,7 @@ Item {
in_txpool = true; in_txpool = true;
} else { } else {
if (blockchainHeight == null) if (blockchainHeight == null)
blockchainHeight = walletManager.blockchainHeight() blockchainHeight = appWindow.currentWallet.blockChainHeight()
confirmations = blockchainHeight - blockHeight - 1 confirmations = blockchainHeight - blockHeight - 1
displayAmount = model.data(idx, TransactionHistoryModel.TransactionDisplayAmountRole); displayAmount = model.data(idx, TransactionHistoryModel.TransactionDisplayAmountRole);
} }

View File

@@ -4,55 +4,38 @@ import QtGraphicalEffects 1.0
import "../../components" as MoneroComponents import "../../components" as MoneroComponents
Item { RowLayout {
id: root id: root
spacing: 10
property bool checked: false; property bool checked: false;
property alias text: content.text property alias text: content.text
signal changed; signal changed;
width: checkBoxLayout.width Rectangle {
height: 22 id: checkbox
anchors.left: parent.left
anchors.top: parent.top
implicitHeight: 22
width: 22
radius: 5
RowLayout { Image {
id: checkBoxLayout id: imageChecked
spacing: 10 visible: root.checked
anchors.centerIn: parent
Item { source: "qrc:///images/uncheckedIcon.png"
height: root.height
width: root.height
Rectangle {
id: checkbox
anchors.fill: parent
radius: 5
Image {
id: imageChecked
visible: root.checked
anchors.centerIn: parent
source: "qrc:///images/uncheckedIcon.png"
}
}
DropShadow {
anchors.fill: source
cached: true
horizontalOffset: 3
verticalOffset: 3
radius: 8.0
samples: 16
color: "#20000000"
smooth: true
source: checkbox
}
}
MoneroComponents.TextPlain {
id: content
font.pixelSize: 14
font.bold: false
color: "white"
text: ""
themeTransition: false
} }
} }
MoneroComponents.TextPlain {
id: content
font.pixelSize: 14
font.bold: false
color: "white"
text: ""
themeTransition: false
}
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
@@ -63,4 +46,16 @@ Item {
changed(); changed();
} }
} }
DropShadow {
anchors.fill: source
cached: true
horizontalOffset: 3
verticalOffset: 3
radius: 8.0
samples: 16
color: "#20000000"
smooth: true
source: checkbox
}
} }

View File

@@ -44,7 +44,7 @@ Rectangle {
property bool showCloseButton: true property bool showCloseButton: true
height: { height: {
if(!persistentSettings.customDecorations) return 0; if(!persistentSettings.customDecorations || isMobile) return 0;
return 50; return 50;
} }

View File

@@ -61,7 +61,9 @@ Rectangle {
property string borderColor: MoneroComponents.Style.blackTheme ? "#808080" : "#B9B9B9" property string borderColor: MoneroComponents.Style.blackTheme ? "#808080" : "#B9B9B9"
property int textMargin: { property int textMargin: {
// left-right margins for a given cell // left-right margins for a given cell
if(appWindow.width < 890){ if(isMobile){
return 10;
} else if(appWindow.width < 890){
return 32; return 32;
} else { } else {
return 64; return 64;

View File

@@ -57,7 +57,7 @@ Rectangle {
anchors.left: parent.left anchors.left: parent.left
anchors.top: parent.top anchors.top: parent.top
anchors.right: parent.right anchors.right: parent.right
anchors.margins: 20 anchors.margins: (isMobile)? 17 : 20
anchors.topMargin: 0 anchors.topMargin: 0
spacing: 30 spacing: 30
@@ -208,11 +208,10 @@ Rectangle {
confirmationDialog.icon = StandardIcon.Question confirmationDialog.icon = StandardIcon.Question
confirmationDialog.cancelText = qsTr("Cancel") confirmationDialog.cancelText = qsTr("Cancel")
confirmationDialog.onAcceptedCallback = function() { confirmationDialog.onAcceptedCallback = function() {
appWindow.closeWallet(function() { walletManager.closeWallet();
walletManager.clearWalletCache(persistentSettings.wallet_path); walletManager.clearWalletCache(persistentSettings.wallet_path);
walletManager.openWalletAsync(persistentSettings.wallet_path, appWindow.walletPassword, walletManager.openWalletAsync(persistentSettings.wallet_path, appWindow.walletPassword,
persistentSettings.nettype, persistentSettings.kdfRounds); persistentSettings.nettype, persistentSettings.kdfRounds);
});
} }
confirmationDialog.onRejectedCallback = null; confirmationDialog.onRejectedCallback = null;
@@ -326,41 +325,6 @@ Rectangle {
font.pixelSize: 14 font.pixelSize: 14
text: isOpenGL ? "OpenGL" : "Low graphics mode" text: isOpenGL ? "OpenGL" : "Low graphics mode"
} }
Rectangle {
visible: isTails
height: 1
Layout.topMargin: 2
Layout.bottomMargin: 2
Layout.fillWidth: true
color: MoneroComponents.Style.dividerColor
opacity: MoneroComponents.Style.dividerOpacity
}
Rectangle {
visible: isTails
height: 1
Layout.topMargin: 2
Layout.bottomMargin: 2
Layout.fillWidth: true
color: MoneroComponents.Style.dividerColor
opacity: MoneroComponents.Style.dividerOpacity
}
MoneroComponents.TextBlock {
visible: isTails
Layout.fillWidth: true
font.pixelSize: 14
text: qsTr("Tails: ") + translationManager.emptyString
}
MoneroComponents.TextBlock {
visible: isTails
Layout.fillWidth: true
color: MoneroComponents.Style.dimmedFontColor
font.pixelSize: 14
text: tailsUsePersistence ? qsTr("persistent") + translationManager.emptyString : qsTr("persistence disabled") + translationManager.emptyString;
}
} }
// Copy info to clipboard // Copy info to clipboard

View File

@@ -47,11 +47,12 @@ Rectangle {
anchors.left: parent.left anchors.left: parent.left
anchors.top: parent.top anchors.top: parent.top
anchors.right: parent.right anchors.right: parent.right
anchors.margins: 20 anchors.margins: (isMobile)? 17 : 20
anchors.topMargin: 0 anchors.topMargin: 0
spacing: 6 spacing: 6
MoneroComponents.CheckBox { MoneroComponents.CheckBox {
visible: !isMobile
id: customDecorationsCheckBox id: customDecorationsCheckBox
checked: persistentSettings.customDecorations checked: persistentSettings.customDecorations
onClicked: Windows.setCustomWindowDecorations(checked) onClicked: Windows.setCustomWindowDecorations(checked)
@@ -59,6 +60,7 @@ Rectangle {
} }
MoneroComponents.CheckBox { MoneroComponents.CheckBox {
visible: !isMobile
id: hideBalanceCheckBox id: hideBalanceCheckBox
checked: persistentSettings.hideBalance checked: persistentSettings.hideBalance
onClicked: { onClicked: {
@@ -68,6 +70,16 @@ Rectangle {
text: qsTr("Hide balance") + translationManager.emptyString text: qsTr("Hide balance") + translationManager.emptyString
} }
MoneroComponents.CheckBox {
visible: !isMobile
id: showPidCheckBox
checked: persistentSettings.showPid
onClicked: {
persistentSettings.showPid = !persistentSettings.showPid
}
text: qsTr("Enable transfer with payment ID (OBSOLETE)") + translationManager.emptyString
}
MoneroComponents.CheckBox { MoneroComponents.CheckBox {
id: themeCheckbox id: themeCheckbox
checked: !MoneroComponents.Style.blackTheme checked: !MoneroComponents.Style.blackTheme
@@ -79,6 +91,7 @@ Rectangle {
} }
MoneroComponents.CheckBox { MoneroComponents.CheckBox {
visible: !isMobile
id: userInActivityCheckbox id: userInActivityCheckbox
checked: persistentSettings.lockOnUserInActivity checked: persistentSettings.lockOnUserInActivity
onClicked: persistentSettings.lockOnUserInActivity = !persistentSettings.lockOnUserInActivity onClicked: persistentSettings.lockOnUserInActivity = !persistentSettings.lockOnUserInActivity
@@ -254,6 +267,14 @@ Rectangle {
appWindow.toggleLanguageView(); appWindow.toggleLanguageView();
} }
} }
MoneroComponents.TextBlock {
visible: isMobile
font.pixelSize: 14
textFormat: Text.RichText
Layout.fillWidth: true
text: qsTr("No Layout options exist yet in mobile mode.") + translationManager.emptyString;
}
} }
ListModel { ListModel {

View File

@@ -47,7 +47,7 @@ Rectangle {
anchors.left: parent.left anchors.left: parent.left
anchors.top: parent.top anchors.top: parent.top
anchors.right: parent.right anchors.right: parent.right
anchors.margins: 20 anchors.margins: (isMobile)? 17 : 20
anchors.topMargin: 0 anchors.topMargin: 0
spacing: 10 spacing: 10
@@ -216,11 +216,7 @@ Rectangle {
onAccepted: { onAccepted: {
if(text.length > 0) { if(text.length > 0) {
consoleArea.logCommand(">>> " + text) consoleArea.logCommand(">>> " + text)
daemonManager.sendCommandAsync(text.split(" "), currentWallet.nettype, function(result) { daemonManager.sendCommand(text, currentWallet.nettype);
if (!result) {
appWindow.showStatusMessage(qsTr("Failed to send command"), 3);
}
});
} }
text = "" text = ""
} }

View File

@@ -42,7 +42,7 @@ Rectangle{
/* main layout */ /* main layout */
ColumnLayout { ColumnLayout {
id: root id: root
anchors.margins: 20 anchors.margins: (isMobile)? 17 : 20
anchors.topMargin: 0 anchors.topMargin: 0
anchors.left: parent.left anchors.left: parent.left
@@ -96,13 +96,17 @@ Rectangle{
anchors.leftMargin: 16 anchors.leftMargin: 16
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
MoneroComponents.Label { MoneroEffects.ImageMask {
fontSize: 32 height: 27
text: FontAwesome.home width: 27
fontFamily: FontAwesome.fontFamilySolid anchors.horizontalCenter: parent.horizontalCenter
anchors.centerIn: parent anchors.verticalCenter: parent.verticalCenter
fontColor: MoneroComponents.Style.defaultFontColor fontAwesomeFallbackIcon: FontAwesome.shield
styleName: "Solid" fontAwesomeFallbackSize: 26
image: "qrc:///images/settings_local.svg"
color: MoneroComponents.Style.defaultFontColor
opacity: MoneroComponents.Style.blackTheme ? 1.0 : 0.8
} }
} }
@@ -198,13 +202,16 @@ Rectangle{
anchors.leftMargin: 16 anchors.leftMargin: 16
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
MoneroComponents.Label { MoneroEffects.ImageMask {
fontSize: 28 height: 29
text: FontAwesome.cloud width: 22
fontFamily: FontAwesome.fontFamilySolid anchors.horizontalCenter: parent.horizontalCenter
styleName: "Solid" anchors.verticalCenter: parent.verticalCenter
anchors.centerIn: parent fontAwesomeFallbackIcon: FontAwesome.cloudDownload
fontColor: MoneroComponents.Style.defaultFontColor fontAwesomeFallbackSize: 26
image: "qrc:///images/settings_remote.svg"
color: MoneroComponents.Style.defaultFontColor
opacity: MoneroComponents.Style.blackTheme ? 1.0 : 0.8
} }
} }
@@ -278,7 +285,7 @@ Rectangle{
spacing: 20 spacing: 20
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 20 Layout.topMargin: 20
visible: persistentSettings.useRemoteNode visible: !isMobile && persistentSettings.useRemoteNode
MoneroComponents.WarningBox { MoneroComponents.WarningBox {
Layout.topMargin: 26 Layout.topMargin: 26
@@ -310,7 +317,7 @@ Rectangle{
} }
GridLayout { GridLayout {
columns: 2 columns: (isMobile) ? 1 : 2
columnSpacing: 32 columnSpacing: 32
MoneroComponents.LineEdit { MoneroComponents.LineEdit {
@@ -370,11 +377,11 @@ Rectangle{
id: localNodeLayout id: localNodeLayout
spacing: 20 spacing: 20
Layout.topMargin: 40 Layout.topMargin: 40
visible: !persistentSettings.useRemoteNode visible: !isMobile && !persistentSettings.useRemoteNode
MoneroComponents.StandardButton { MoneroComponents.StandardButton {
small: true small: true
text: (appWindow.daemonRunning ? qsTr("Stop daemon") : qsTr("Start daemon")) + translationManager.emptyString text: (appWindow.daemonRunning ? qsTr("Stop local node") : qsTr("Start daemon")) + translationManager.emptyString
onClicked: { onClicked: {
if (appWindow.daemonRunning) { if (appWindow.daemonRunning) {
appWindow.stopDaemon(); appWindow.stopDaemon();
@@ -396,7 +403,6 @@ Rectangle{
labelText: qsTr("Blockchain location") + style + qsTr(" <a href='#'> (change)</a>") + translationManager.emptyString labelText: qsTr("Blockchain location") + style + qsTr(" <a href='#'> (change)</a>") + translationManager.emptyString
placeholderText: qsTr("(default)") + translationManager.emptyString placeholderText: qsTr("(default)") + translationManager.emptyString
placeholderFontSize: 15 placeholderFontSize: 15
readOnly: true
text: { text: {
if(persistentSettings.blockchainDataDir.length > 0){ if(persistentSettings.blockchainDataDir.length > 0){
return persistentSettings.blockchainDataDir; return persistentSettings.blockchainDataDir;
@@ -429,7 +435,7 @@ Rectangle{
} }
RowLayout { RowLayout {
visible: !persistentSettings.useRemoteNode visible: !isMobile && !persistentSettings.useRemoteNode
ColumnLayout { ColumnLayout {
Layout.fillWidth: true Layout.fillWidth: true
@@ -451,11 +457,7 @@ Rectangle{
} }
} }
onEditingFinished: { onEditingFinished: {
if (daemonAddrText == "auto") { persistentSettings.bootstrapNodeAddress = daemonAddrText ? bootstrapNodeEdit.getAddress() : "";
persistentSettings.bootstrapNodeAddress = daemonAddrText;
} else {
persistentSettings.bootstrapNodeAddress = daemonAddrText ? bootstrapNodeEdit.getAddress() : "";
}
console.log("setting bootstrap node to " + persistentSettings.bootstrapNodeAddress) console.log("setting bootstrap node to " + persistentSettings.bootstrapNodeAddress)
} }
} }

View File

@@ -45,7 +45,7 @@ Rectangle {
anchors.left: parent.left anchors.left: parent.left
anchors.top: parent.top anchors.top: parent.top
anchors.right: parent.right anchors.right: parent.right
anchors.margins: 20 anchors.margins: (isMobile)? 17 : 20
anchors.topMargin: 0 anchors.topMargin: 0
spacing: 0 spacing: 0
@@ -339,7 +339,7 @@ Rectangle {
onClicked: { onClicked: {
passwordDialog.onAcceptedCallback = function() { passwordDialog.onAcceptedCallback = function() {
if(appWindow.walletPassword === passwordDialog.password){ if(appWindow.walletPassword === passwordDialog.password){
passwordDialog.openNewPasswordDialog() newPasswordDialog.open()
} else { } else {
informationPopup.title = qsTr("Error") + translationManager.emptyString; informationPopup.title = qsTr("Error") + translationManager.emptyString;
informationPopup.text = qsTr("Wrong password") + translationManager.emptyString; informationPopup.text = qsTr("Wrong password") + translationManager.emptyString;

18
qml.qrc
View File

@@ -96,7 +96,9 @@
<file>pages/SharedRingDB.qml</file> <file>pages/SharedRingDB.qml</file>
<file>components/effects/ImageMask.qml</file> <file>components/effects/ImageMask.qml</file>
<file>components/IconButton.qml</file> <file>components/IconButton.qml</file>
<file>components/PassphraseDialog.qml</file>
<file>components/PasswordDialog.qml</file> <file>components/PasswordDialog.qml</file>
<file>components/NewPasswordDialog.qml</file>
<file>components/InputDialog.qml</file> <file>components/InputDialog.qml</file>
<file>components/ProcessingSplash.qml</file> <file>components/ProcessingSplash.qml</file>
<file>components/ProgressBar.qml</file> <file>components/ProgressBar.qml</file>
@@ -107,14 +109,13 @@
<file>components/DaemonConsole.qml</file> <file>components/DaemonConsole.qml</file>
<file>components/QRCodeScanner.qml</file> <file>components/QRCodeScanner.qml</file>
<file>components/Notifier.qml</file> <file>components/Notifier.qml</file>
<file>components/MobileHeader.qml</file>
<file>components/TextBlock.qml</file> <file>components/TextBlock.qml</file>
<file>components/RemoteNodeEdit.qml</file> <file>components/RemoteNodeEdit.qml</file>
<file>pages/Keys.qml</file> <file>pages/Keys.qml</file>
<file>images/appicon.ico</file> <file>images/appicon.ico</file>
<file>images/card-background-black.png</file> <file>images/card-background.png</file>
<file>images/card-background-black@2x.png</file> <file>images/card-background@2x.png</file>
<file>images/card-background-white.png</file>
<file>images/card-background-white@2x.png</file>
<file>images/moneroLogo_white.png</file> <file>images/moneroLogo_white.png</file>
<file>images/question.png</file> <file>images/question.png</file>
<file>images/question@2x.png</file> <file>images/question@2x.png</file>
@@ -168,6 +169,8 @@
<file>pages/settings/SettingsLayout.qml</file> <file>pages/settings/SettingsLayout.qml</file>
<file>pages/settings/SettingsInfo.qml</file> <file>pages/settings/SettingsInfo.qml</file>
<file>pages/settings/Navbar.qml</file> <file>pages/settings/Navbar.qml</file>
<file>images/settings_local.svg</file>
<file>images/settings_remote.svg</file>
<file>components/WarningBox.qml</file> <file>components/WarningBox.qml</file>
<file>images/miningxmr.png</file> <file>images/miningxmr.png</file>
<file>images/miningxmr@2x.png</file> <file>images/miningxmr@2x.png</file>
@@ -179,9 +182,7 @@
<file>images/merchant/arrow_right.png</file> <file>images/merchant/arrow_right.png</file>
<file>images/merchant/bg.png</file> <file>images/merchant/bg.png</file>
<file>images/merchant/input_box.png</file> <file>images/merchant/input_box.png</file>
<file>fonts/FontAwesome/fa-brands-400.ttf</file> <file>fonts/FontAwesome/fontawesome-webfont.ttf</file>
<file>fonts/FontAwesome/fa-regular-400.ttf</file>
<file>fonts/FontAwesome/fa-solid-900.ttf</file>
<file>fonts/FontAwesome/FontAwesome.qml</file> <file>fonts/FontAwesome/FontAwesome.qml</file>
<file>fonts/FontAwesome/Object.qml</file> <file>fonts/FontAwesome/Object.qml</file>
<file>fonts/FontAwesome/qmldir</file> <file>fonts/FontAwesome/qmldir</file>
@@ -237,6 +238,7 @@
<file>images/middlePanelShadow.png</file> <file>images/middlePanelShadow.png</file>
<file>images/themes/white/titlebarLogo@2x.png</file> <file>images/themes/white/titlebarLogo@2x.png</file>
<file>images/themes/white/titlebarLogo.png</file> <file>images/themes/white/titlebarLogo.png</file>
<file>images/sidebar.svg</file>
<file>images/fullscreen.svg</file> <file>images/fullscreen.svg</file>
<file>images/close.svg</file> <file>images/close.svg</file>
<file>images/minimize.svg</file> <file>images/minimize.svg</file>
@@ -244,12 +246,12 @@
<file>images/themes/white/fullscreen.svg</file> <file>images/themes/white/fullscreen.svg</file>
<file>images/themes/white/minimize.svg</file> <file>images/themes/white/minimize.svg</file>
<file>images/themes/white/question.svg</file> <file>images/themes/white/question.svg</file>
<file>images/themes/white/expand.svg</file>
<file>components/effects/ColorTransition.qml</file> <file>components/effects/ColorTransition.qml</file>
<file>components/effects/GradientBackground.qml</file> <file>components/effects/GradientBackground.qml</file>
<file>images/check-white.svg</file> <file>images/check-white.svg</file>
<file>images/copy.svg</file> <file>images/copy.svg</file>
<file>images/edit.svg</file> <file>images/edit.svg</file>
<file>images/arrow-right-in-circle-outline-medium-white.svg</file> <file>images/arrow-right-in-circle-outline-medium-white.svg</file>
<file>images/tails-grey.png</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@@ -43,7 +43,7 @@
#include <QMap> #include <QMap>
namespace { namespace {
static const int DAEMON_START_TIMEOUT_SECONDS = 60; static const int DAEMON_START_TIMEOUT_SECONDS = 30;
} }
DaemonManager * DaemonManager::m_instance = nullptr; DaemonManager * DaemonManager::m_instance = nullptr;
@@ -61,7 +61,7 @@ DaemonManager *DaemonManager::instance(const QStringList *args)
return m_instance; return m_instance;
} }
bool DaemonManager::start(const QString &flags, NetworkType::Type nettype, const QString &dataDir, const QString &bootstrapNodeAddress, bool noSync /* = false*/) bool DaemonManager::start(const QString &flags, NetworkType::Type nettype, const QString &dataDir, const QString &bootstrapNodeAddress)
{ {
// prepare command line arguments and pass to monerod // prepare command line arguments and pass to monerod
QStringList arguments; QStringList arguments;
@@ -99,10 +99,6 @@ bool DaemonManager::start(const QString &flags, NetworkType::Type nettype, const
arguments << "--bootstrap-daemon-address" << bootstrapNodeAddress; arguments << "--bootstrap-daemon-address" << bootstrapNodeAddress;
} }
if (noSync) {
arguments << "--no-sync";
}
arguments << "--check-updates" << "disabled"; arguments << "--check-updates" << "disabled";
// --max-concurrency based on threads available. max: 6 // --max-concurrency based on threads available. max: 6
@@ -135,13 +131,11 @@ bool DaemonManager::start(const QString &flags, NetworkType::Type nettype, const
} }
// Start start watcher // Start start watcher
m_scheduler.run([this, nettype, noSync] { m_scheduler.run([this, nettype] {
if (startWatcher(nettype)) { if (startWatcher(nettype))
emit daemonStarted(); emit daemonStarted();
m_noSync = noSync; else
} else {
emit daemonStartFailure(); emit daemonStartFailure();
}
}); });
return true; return true;
@@ -150,7 +144,7 @@ bool DaemonManager::start(const QString &flags, NetworkType::Type nettype, const
bool DaemonManager::stop(NetworkType::Type nettype) bool DaemonManager::stop(NetworkType::Type nettype)
{ {
QString message; QString message;
sendCommand({"exit"}, nettype, message); sendCommand("exit", nettype, message);
qDebug() << message; qDebug() << message;
// Start stop watcher - Will kill if not shutting down // Start stop watcher - Will kill if not shutting down
@@ -240,27 +234,26 @@ void DaemonManager::printError()
bool DaemonManager::running(NetworkType::Type nettype) const bool DaemonManager::running(NetworkType::Type nettype) const
{ {
QString status; QString status;
sendCommand({"sync_info"}, nettype, status); sendCommand("status", nettype, status);
qDebug() << status; qDebug() << status;
return status.contains("Height:"); // `./monerod status` returns BUSY when syncing.
// Treat busy as connected, until fixed upstream.
if (status.contains("Height:") || status.contains("BUSY") ) {
return true;
}
return false;
} }
bool DaemonManager::sendCommand(const QString &cmd, NetworkType::Type nettype) const
bool DaemonManager::noSync() const noexcept
{ {
return m_noSync; QString message;
return sendCommand(cmd, nettype, message);
} }
void DaemonManager::runningAsync(NetworkType::Type nettype, const QJSValue& callback) const bool DaemonManager::sendCommand(const QString &cmd, NetworkType::Type nettype, QString &message) const
{
m_scheduler.run([this, nettype] {
return QJSValueList({running(nettype)});
}, callback);
}
bool DaemonManager::sendCommand(const QStringList &cmd, NetworkType::Type nettype, QString &message) const
{ {
QProcess p; QProcess p;
QStringList external_cmd(cmd); QStringList external_cmd;
external_cmd << cmd;
// Add network type flag if needed // Add network type flag if needed
if (nettype == NetworkType::TESTNET) if (nettype == NetworkType::TESTNET)
@@ -279,14 +272,6 @@ bool DaemonManager::sendCommand(const QStringList &cmd, NetworkType::Type nettyp
return started; return started;
} }
void DaemonManager::sendCommandAsync(const QStringList &cmd, NetworkType::Type nettype, const QJSValue& callback) const
{
m_scheduler.run([this, cmd, nettype] {
QString message;
return QJSValueList({sendCommand(cmd, nettype, message)});
}, callback);
}
void DaemonManager::exit() void DaemonManager::exit()
{ {
qDebug("DaemonManager: exit()"); qDebug("DaemonManager: exit()");

View File

@@ -44,21 +44,19 @@ public:
static DaemonManager * instance(const QStringList *args); static DaemonManager * instance(const QStringList *args);
Q_INVOKABLE bool start(const QString &flags, NetworkType::Type nettype, const QString &dataDir = "", const QString &bootstrapNodeAddress = "", bool noSync = false); Q_INVOKABLE bool start(const QString &flags, NetworkType::Type nettype, const QString &dataDir = "", const QString &bootstrapNodeAddress = "");
Q_INVOKABLE bool stop(NetworkType::Type nettype); Q_INVOKABLE bool stop(NetworkType::Type nettype);
Q_INVOKABLE bool noSync() const noexcept;
// return true if daemon process is started // return true if daemon process is started
Q_INVOKABLE void runningAsync(NetworkType::Type nettype, const QJSValue& callback) const; Q_INVOKABLE bool running(NetworkType::Type nettype) const;
// Send daemon command from qml and prints output in console window. // Send daemon command from qml and prints output in console window.
Q_INVOKABLE void sendCommandAsync(const QStringList &cmd, NetworkType::Type nettype, const QJSValue& callback) const; Q_INVOKABLE bool sendCommand(const QString &cmd, NetworkType::Type nettype) const;
Q_INVOKABLE void exit(); Q_INVOKABLE void exit();
Q_INVOKABLE QVariantMap validateDataDir(const QString &dataDir) const; Q_INVOKABLE QVariantMap validateDataDir(const QString &dataDir) const;
private: private:
bool running(NetworkType::Type nettype) const; bool sendCommand(const QString &cmd, NetworkType::Type nettype, QString &message) const;
bool sendCommand(const QStringList &cmd, NetworkType::Type nettype, QString &message) const;
bool startWatcher(NetworkType::Type nettype) const; bool startWatcher(NetworkType::Type nettype) const;
bool stopWatcher(NetworkType::Type nettype) const; bool stopWatcher(NetworkType::Type nettype) const;
signals: signals:
@@ -83,9 +81,8 @@ private:
QString m_monerod; QString m_monerod;
bool m_has_daemon = true; bool m_has_daemon = true;
bool m_app_exit = false; bool m_app_exit = false;
bool m_noSync = false;
mutable FutureScheduler m_scheduler; FutureScheduler m_scheduler;
}; };
#endif // DAEMONMANAGER_H #endif // DAEMONMANAGER_H

View File

@@ -40,7 +40,7 @@ QString UnsignedTransaction::errorString() const
return QString::fromStdString(m_pimpl->errorString()); return QString::fromStdString(m_pimpl->errorString());
} }
quint64 UnsignedTransaction::amount(size_t index) const quint64 UnsignedTransaction::amount(int index) const
{ {
std::vector<uint64_t> arr = m_pimpl->amount(); std::vector<uint64_t> arr = m_pimpl->amount();
if(index > arr.size() - 1) if(index > arr.size() - 1)
@@ -48,7 +48,7 @@ quint64 UnsignedTransaction::amount(size_t index) const
return arr[index]; return arr[index];
} }
quint64 UnsignedTransaction::fee(size_t index) const quint64 UnsignedTransaction::fee(int index) const
{ {
std::vector<uint64_t> arr = m_pimpl->fee(); std::vector<uint64_t> arr = m_pimpl->fee();
if(index > arr.size() - 1) if(index > arr.size() - 1)
@@ -56,7 +56,7 @@ quint64 UnsignedTransaction::fee(size_t index) const
return arr[index]; return arr[index];
} }
quint64 UnsignedTransaction::mixin(size_t index) const quint64 UnsignedTransaction::mixin(int index) const
{ {
std::vector<uint64_t> arr = m_pimpl->mixin(); std::vector<uint64_t> arr = m_pimpl->mixin();
if(index > arr.size() - 1) if(index > arr.size() - 1)

View File

@@ -56,9 +56,9 @@ public:
Status status() const; Status status() const;
QString errorString() const; QString errorString() const;
Q_INVOKABLE quint64 amount(size_t index) const; Q_INVOKABLE quint64 amount(int index) const;
Q_INVOKABLE quint64 fee(size_t index) const; Q_INVOKABLE quint64 fee(int index) const;
Q_INVOKABLE quint64 mixin(size_t index) const; Q_INVOKABLE quint64 mixin(int index) const;
QStringList recipientAddress() const; QStringList recipientAddress() const;
QStringList paymentId() const; QStringList paymentId() const;
quint64 txCount() const; quint64 txCount() const;

View File

@@ -206,7 +206,7 @@ bool Wallet::store(const QString &path)
return m_walletImpl->store(path.toStdString()); return m_walletImpl->store(path.toStdString());
} }
bool Wallet::init(const QString &daemonAddress, bool trustedDaemon, quint64 upperTransactionLimit, bool isRecovering, bool isRecoveringFromDevice, quint64 restoreHeight) bool Wallet::init(const QString &daemonAddress, quint64 upperTransactionLimit, bool isRecovering, bool isRecoveringFromDevice, quint64 restoreHeight)
{ {
qDebug() << "init non async"; qDebug() << "init non async";
if (isRecovering){ if (isRecovering){
@@ -221,7 +221,6 @@ bool Wallet::init(const QString &daemonAddress, bool trustedDaemon, quint64 uppe
m_walletImpl->setRefreshFromBlockHeight(restoreHeight); m_walletImpl->setRefreshFromBlockHeight(restoreHeight);
} }
m_walletImpl->init(daemonAddress.toStdString(), upperTransactionLimit, m_daemonUsername.toStdString(), m_daemonPassword.toStdString()); m_walletImpl->init(daemonAddress.toStdString(), upperTransactionLimit, m_daemonUsername.toStdString(), m_daemonPassword.toStdString());
setTrustedDaemon(trustedDaemon);
return true; return true;
} }
@@ -232,7 +231,7 @@ void Wallet::setDaemonLogin(const QString &daemonUsername, const QString &daemon
m_daemonPassword = daemonPassword; m_daemonPassword = daemonPassword;
} }
void Wallet::initAsync(const QString &daemonAddress, bool trustedDaemon, quint64 upperTransactionLimit, bool isRecovering, bool isRecoveringFromDevice, quint64 restoreHeight) void Wallet::initAsync(const QString &daemonAddress, quint64 upperTransactionLimit, bool isRecovering, bool isRecoveringFromDevice, quint64 restoreHeight)
{ {
qDebug() << "initAsync: " + daemonAddress; qDebug() << "initAsync: " + daemonAddress;
// Change status to disconnected if connected // Change status to disconnected if connected
@@ -241,28 +240,19 @@ void Wallet::initAsync(const QString &daemonAddress, bool trustedDaemon, quint64
emit connectionStatusChanged(m_connectionStatus); emit connectionStatusChanged(m_connectionStatus);
} }
m_scheduler.run([this, daemonAddress, trustedDaemon, upperTransactionLimit, isRecovering, isRecoveringFromDevice, restoreHeight] { m_scheduler.run([this, daemonAddress, upperTransactionLimit, isRecovering, isRecoveringFromDevice, restoreHeight] {
bool success = init(daemonAddress, trustedDaemon, upperTransactionLimit, isRecovering, isRecoveringFromDevice, restoreHeight); bool success = init(daemonAddress, upperTransactionLimit, isRecovering, isRecoveringFromDevice, restoreHeight);
if (success) if (success)
{ {
emit walletCreationHeightChanged(); emit walletCreationHeightChanged();
qDebug() << "init async finished - starting refresh"; qDebug() << "init async finished - starting refresh";
connected(true); connected(true);
m_walletImpl->startRefresh(); m_walletImpl->startRefresh();
} }
}); });
} }
bool Wallet::isHwBacked() const
{
return m_walletImpl->getDeviceType() != Monero::Wallet::Device_Software;
}
bool Wallet::isLedger() const
{
return m_walletImpl->getDeviceType() == Monero::Wallet::Device_Ledger;
}
//! create a view only wallet //! create a view only wallet
bool Wallet::createViewOnly(const QString &path, const QString &password) const bool Wallet::createViewOnly(const QString &path, const QString &password) const
{ {
@@ -345,13 +335,6 @@ void Wallet::setSubaddressLabel(quint32 accountIndex, quint32 addressIndex, cons
{ {
m_walletImpl->setSubaddressLabel(accountIndex, addressIndex, label.toStdString()); m_walletImpl->setSubaddressLabel(accountIndex, addressIndex, label.toStdString());
} }
void Wallet::deviceShowAddressAsync(quint32 accountIndex, quint32 addressIndex, const QString &paymentId)
{
m_scheduler.run([this, accountIndex, addressIndex, paymentId] {
m_walletImpl->deviceShowAddress(accountIndex, addressIndex, paymentId.toStdString());
emit deviceShowAddressShowed();
});
}
void Wallet::refreshHeightAsync() void Wallet::refreshHeightAsync()
{ {
@@ -541,8 +524,7 @@ bool Wallet::submitTxFile(const QString &fileName) const
void Wallet::commitTransactionAsync(PendingTransaction *t) void Wallet::commitTransactionAsync(PendingTransaction *t)
{ {
m_scheduler.run([this, t] { m_scheduler.run([this, t] {
auto txIdList = t->txid(); // retrieve before commit emit transactionCommitted(t->commit(), t, t->txid());
emit transactionCommitted(t->commit(), t, txIdList);
}); });
} }
@@ -640,15 +622,6 @@ void Wallet::setPaymentId(const QString &paymentId)
m_paymentId = paymentId; m_paymentId = paymentId;
} }
QString Wallet::getCacheAttribute(const QString &key) const {
return QString::fromStdString(m_walletImpl->getCacheAttribute(key.toStdString()));
}
bool Wallet::setCacheAttribute(const QString &key, const QString &val)
{
return m_walletImpl->setCacheAttribute(key.toStdString(), val.toStdString());
}
bool Wallet::setUserNote(const QString &txid, const QString &note) bool Wallet::setUserNote(const QString &txid, const QString &note)
{ {
return m_walletImpl->setUserNote(txid.toStdString(), note.toStdString()); return m_walletImpl->setUserNote(txid.toStdString(), note.toStdString());
@@ -963,16 +936,16 @@ Wallet::Wallet(Monero::Wallet *w, QObject *parent)
, m_historyModel(nullptr) , m_historyModel(nullptr)
, m_addressBook(nullptr) , m_addressBook(nullptr)
, m_addressBookModel(nullptr) , m_addressBookModel(nullptr)
, m_subaddress(nullptr)
, m_subaddressModel(nullptr)
, m_subaddressAccount(nullptr)
, m_subaddressAccountModel(nullptr)
, m_daemonBlockChainHeight(0) , m_daemonBlockChainHeight(0)
, m_daemonBlockChainHeightTtl(DAEMON_BLOCKCHAIN_HEIGHT_CACHE_TTL_SECONDS) , m_daemonBlockChainHeightTtl(DAEMON_BLOCKCHAIN_HEIGHT_CACHE_TTL_SECONDS)
, m_daemonBlockChainTargetHeight(0) , m_daemonBlockChainTargetHeight(0)
, m_daemonBlockChainTargetHeightTtl(DAEMON_BLOCKCHAIN_TARGET_HEIGHT_CACHE_TTL_SECONDS) , m_daemonBlockChainTargetHeightTtl(DAEMON_BLOCKCHAIN_TARGET_HEIGHT_CACHE_TTL_SECONDS)
, m_connectionStatusTtl(WALLET_CONNECTION_STATUS_CACHE_TTL_SECONDS) , m_connectionStatusTtl(WALLET_CONNECTION_STATUS_CACHE_TTL_SECONDS)
, m_currentSubaddressAccount(0) , m_currentSubaddressAccount(0)
, m_subaddress(nullptr)
, m_subaddressModel(nullptr)
, m_subaddressAccount(nullptr)
, m_subaddressAccountModel(nullptr)
, m_scheduler(this) , m_scheduler(this)
{ {
m_history = new TransactionHistory(m_walletImpl->history(), this); m_history = new TransactionHistory(m_walletImpl->history(), this);

View File

@@ -144,8 +144,11 @@ public:
//! empty path stores in current location //! empty path stores in current location
Q_INVOKABLE bool store(const QString &path = ""); Q_INVOKABLE bool store(const QString &path = "");
//! initializes wallet
Q_INVOKABLE bool init(const QString &daemonAddress, quint64 upperTransactionLimit = 0, bool isRecovering = false, bool isRecoveringFromDevice = false, quint64 restoreHeight = 0);
//! initializes wallet asynchronously //! initializes wallet asynchronously
Q_INVOKABLE void initAsync(const QString &daemonAddress, bool trustedDaemon = false, quint64 upperTransactionLimit = 0, bool isRecovering = false, bool isRecoveringFromDevice = false, quint64 restoreHeight = 0); Q_INVOKABLE void initAsync(const QString &daemonAddress, quint64 upperTransactionLimit = 0, bool isRecovering = false, bool isRecoveringFromDevice = false, quint64 restoreHeight = 0);
// Set daemon rpc user/pass // Set daemon rpc user/pass
Q_INVOKABLE void setDaemonLogin(const QString &daemonUsername = "", const QString &daemonPassword = ""); Q_INVOKABLE void setDaemonLogin(const QString &daemonUsername = "", const QString &daemonPassword = "");
@@ -176,11 +179,6 @@ public:
Q_INVOKABLE void addSubaddress(const QString& label); Q_INVOKABLE void addSubaddress(const QString& label);
Q_INVOKABLE QString getSubaddressLabel(quint32 accountIndex, quint32 addressIndex) const; Q_INVOKABLE QString getSubaddressLabel(quint32 accountIndex, quint32 addressIndex) const;
Q_INVOKABLE void setSubaddressLabel(quint32 accountIndex, quint32 addressIndex, const QString &label); Q_INVOKABLE void setSubaddressLabel(quint32 accountIndex, quint32 addressIndex, const QString &label);
Q_INVOKABLE void deviceShowAddressAsync(quint32 accountIndex, quint32 addressIndex, const QString &paymentId);
//! hw-device backed wallets
Q_INVOKABLE bool isHwBacked() const;
Q_INVOKABLE bool isLedger() const;
//! returns if view only wallet //! returns if view only wallet
Q_INVOKABLE bool viewOnly() const; Q_INVOKABLE bool viewOnly() const;
@@ -290,10 +288,6 @@ public:
void setPaymentId(const QString &paymentId); void setPaymentId(const QString &paymentId);
//! Namespace your cacheAttribute keys to avoid collisions
Q_INVOKABLE bool setCacheAttribute(const QString &key, const QString &val);
Q_INVOKABLE QString getCacheAttribute(const QString &key) const;
Q_INVOKABLE bool setUserNote(const QString &txid, const QString &note); Q_INVOKABLE bool setUserNote(const QString &txid, const QString &note);
Q_INVOKABLE QString getUserNote(const QString &txid) const; Q_INVOKABLE QString getUserNote(const QString &txid) const;
Q_INVOKABLE QString getTxKey(const QString &txid) const; Q_INVOKABLE QString getTxKey(const QString &txid) const;
@@ -357,9 +351,8 @@ signals:
void walletCreationHeightChanged(); void walletCreationHeightChanged();
void deviceButtonRequest(quint64 buttonCode); void deviceButtonRequest(quint64 buttonCode);
void deviceButtonPressed(); void deviceButtonPressed();
void transactionCommitted(bool status, PendingTransaction *t, const QStringList& txid); void transactionCommitted(bool status, PendingTransaction *t, QStringList txid);
void heightRefreshed(quint64 walletHeight, quint64 daemonHeight, quint64 targetHeight) const; void heightRefreshed(quint64 walletHeight, quint64 daemonHeight, quint64 targetHeight) const;
void deviceShowAddressShowed();
// emitted when transaction is created async // emitted when transaction is created async
void transactionCreated(PendingTransaction * transaction, QString address, QString paymentId, quint32 mixinCount); void transactionCreated(PendingTransaction * transaction, QString address, QString paymentId, quint32 mixinCount);
@@ -381,9 +374,6 @@ private:
//! returns daemon's blockchain target height //! returns daemon's blockchain target height
quint64 daemonBlockChainTargetHeight() const; quint64 daemonBlockChainTargetHeight() const;
//! initializes wallet
bool init(const QString &daemonAddress, bool trustedDaemon, quint64 upperTransactionLimit, bool isRecovering, bool isRecoveringFromDevice, quint64 restoreHeight);
private: private:
friend class WalletManager; friend class WalletManager;
friend class WalletListenerImpl; friend class WalletListenerImpl;
@@ -395,8 +385,6 @@ private:
mutable TransactionHistoryModel * m_historyModel; mutable TransactionHistoryModel * m_historyModel;
mutable TransactionHistorySortFilterModel * m_historySortFilterModel; mutable TransactionHistorySortFilterModel * m_historySortFilterModel;
QString m_paymentId; QString m_paymentId;
AddressBook * m_addressBook;
mutable AddressBookModel * m_addressBookModel;
mutable QTime m_daemonBlockChainHeightTime; mutable QTime m_daemonBlockChainHeightTime;
mutable quint64 m_daemonBlockChainHeight; mutable quint64 m_daemonBlockChainHeight;
int m_daemonBlockChainHeightTtl; int m_daemonBlockChainHeightTtl;
@@ -408,6 +396,8 @@ private:
mutable QTime m_connectionStatusTime; mutable QTime m_connectionStatusTime;
mutable bool m_initialized; mutable bool m_initialized;
uint32_t m_currentSubaddressAccount; uint32_t m_currentSubaddressAccount;
AddressBook * m_addressBook;
mutable AddressBookModel * m_addressBookModel;
Subaddress * m_subaddress; Subaddress * m_subaddress;
mutable SubaddressModel * m_subaddressModel; mutable SubaddressModel * m_subaddressModel;
SubaddressAccount * m_subaddressAccount; SubaddressAccount * m_subaddressAccount;

View File

@@ -66,7 +66,7 @@ public:
} }
auto tmpPass = m_mgr->m_passphrase.toStdString(); auto tmpPass = m_mgr->m_passphrase.toStdString();
m_mgr->m_passphrase = QString(); m_mgr->m_passphrase = QString::null;
return Monero::optional<std::string>(tmpPass); return Monero::optional<std::string>(tmpPass);
} }
@@ -228,11 +228,11 @@ QString WalletManager::closeWallet()
return result; return result;
} }
void WalletManager::closeWalletAsync(const QJSValue& callback) void WalletManager::closeWalletAsync()
{ {
m_scheduler.run([this] { m_scheduler.run([this] {
return QJSValueList({closeWallet()}); emit walletClosed(closeWallet());
}, callback); });
} }
bool WalletManager::walletExists(const QString &path) const bool WalletManager::walletExists(const QString &path) const
@@ -376,7 +376,7 @@ bool WalletManager::localDaemonSynced() const
bool WalletManager::isDaemonLocal(const QString &daemon_address) const bool WalletManager::isDaemonLocal(const QString &daemon_address) const
{ {
return daemon_address.isEmpty() ? false : Monero::Utils::isAddressLocal(daemon_address.toStdString()); return Monero::Utils::isAddressLocal(daemon_address.toStdString());
} }
QString WalletManager::resolveOpenAlias(const QString &address) const QString WalletManager::resolveOpenAlias(const QString &address) const

View File

@@ -117,7 +117,7 @@ public:
/*! /*!
* \brief closeWalletAsync - asynchronous version of "closeWallet" * \brief closeWalletAsync - asynchronous version of "closeWallet"
*/ */
Q_INVOKABLE void closeWalletAsync(const QJSValue& callback); Q_INVOKABLE void closeWalletAsync();
//! checks is given filename is a wallet; //! checks is given filename is a wallet;
Q_INVOKABLE bool walletExists(const QString &path) const; Q_INVOKABLE bool walletExists(const QString &path) const;
@@ -192,6 +192,7 @@ signals:
void walletPassphraseNeeded(); void walletPassphraseNeeded();
void deviceButtonRequest(quint64 buttonCode); void deviceButtonRequest(quint64 buttonCode);
void deviceButtonPressed(); void deviceButtonPressed();
void walletClosed(const QString &walletAddress);
void checkUpdatesComplete(const QString &result) const; void checkUpdatesComplete(const QString &result) const;
void miningStatus(bool isMining) const; void miningStatus(bool isMining) const;

View File

@@ -50,7 +50,7 @@ void AddressBookModel::endReset(){
endResetModel(); endResetModel();
} }
int AddressBookModel::rowCount(const QModelIndex &) const int AddressBookModel::rowCount(const QModelIndex &parent) const
{ {
return m_addressBook->count(); return m_addressBook->count();
} }

View File

@@ -49,7 +49,7 @@ void SubaddressAccountModel::endReset(){
endResetModel(); endResetModel();
} }
int SubaddressAccountModel::rowCount(const QModelIndex &) const int SubaddressAccountModel::rowCount(const QModelIndex &parent) const
{ {
return m_subaddressAccount->count(); return m_subaddressAccount->count();
} }

View File

@@ -50,7 +50,7 @@ void SubaddressModel::endReset(){
endResetModel(); endResetModel();
} }
int SubaddressModel::rowCount(const QModelIndex &) const int SubaddressModel::rowCount(const QModelIndex &parent) const
{ {
return m_subaddress->count(); return m_subaddress->count();
} }

View File

@@ -38,7 +38,7 @@ QPair<bool, QFuture<void>> FutureScheduler::run(std::function<void()> function)
}); });
} }
QPair<bool, QFuture<QJSValueList>> FutureScheduler::run(std::function<QJSValueList() noexcept> function, const QJSValue &callback) QPair<bool, QFuture<QJSValueList>> FutureScheduler::run(std::function<QJSValueList() noexcept> function, const QJSValue &callback) noexcept
{ {
if (!callback.isCallable()) if (!callback.isCallable())
{ {

View File

@@ -20,9 +20,9 @@ public:
~FutureScheduler(); ~FutureScheduler();
void shutdownWaitForFinished() noexcept; void shutdownWaitForFinished() noexcept;
QPair<bool, QFuture<void>> run(std::function<void()> function) noexcept; QPair<bool, QFuture<void>> run(std::function<void()> function) noexcept;
QPair<bool, QFuture<QJSValueList>> run(std::function<QJSValueList() noexcept> function, const QJSValue &callback); QPair<bool, QFuture<QJSValueList>> run(std::function<QJSValueList() noexcept> function, const QJSValue &callback) noexcept;
private: private:
bool add() noexcept; bool add() noexcept;
@@ -38,7 +38,7 @@ private:
watcher->moveToThread(schedulerThread); watcher->moveToThread(schedulerThread);
} }
watcher->setParent(this); watcher->setParent(this);
return watcher; return watcher;
} }

View File

@@ -36,9 +36,9 @@
#include <QMutex> #include <QMutex>
#include <QMutexLocker> #include <QMutexLocker>
#include <QString> #include <QString>
#include "libwalletqt/WalletManager.h" #include "src/libwalletqt/WalletManager.h"
#include "NetworkType.h" #include "src/NetworkType.h"
#include "qt/utils.h" #include "src/qt/utils.h"
#include "KeysFiles.h" #include "KeysFiles.h"

View File

@@ -30,8 +30,8 @@
#define KEYSFILES_H #define KEYSFILES_H
#include <qqmlcontext.h> #include <qqmlcontext.h>
#include "libwalletqt/WalletManager.h" #include "src/libwalletqt/WalletManager.h"
#include "NetworkType.h" #include "src/NetworkType.h"
#include <QtCore> #include <QtCore>
class WalletKeysFiles class WalletKeysFiles

View File

@@ -1,208 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
****************************************************************************/
// 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.
#include <QtCore>
#include <QMetaObject>
#include <QSettings>
#include <QPointer>
#include <QJSValue>
#include <QHash>
#include <QMetaProperty>
#include "qt/MoneroSettings.h"
/*!
\qmlmodule moneroSettings 1.0
\title Monero Settings QML Component
\ingroup qmlmodules
\brief Provides persistent platform-independent application settings.
This component was introduced in order to have control over where the
configuration file is written. This is needed for Tails OS and
portable installations.
For more information, see: https://doc.qt.io/qt-5/qml-qt-labs-settings-settings.html and
https://github.com/qt/qtdeclarative/blob/v5.12.0/src/imports/settings/qqmlsettings.cpp
To use this module, import the module with the following line:
\code
import moneroComponents.Settings 1.0
\endcode
Usage:
\code
MoneroSettings { id: persistentSettings, property bool foo: true }
\endcode
@TODO: Remove this QML component after migrating to Qt >= 5.12.0, as
`Qt.labs.settings` provides the fileName via a Q_PROPERTY
*/
void MoneroSettings::load()
{
const QMetaObject *mo = this->metaObject();
const int offset = mo->propertyOffset();
const int count = mo->propertyCount();
for (int i = offset; i < count; ++i) {
QMetaProperty property = mo->property(i);
const QVariant previousValue = readProperty(property);
const QVariant currentValue = this->m_settings->value(property.name(), previousValue);
if (!currentValue.isNull() && (!previousValue.isValid()
|| (currentValue.canConvert(previousValue.type()) && previousValue != currentValue))) {
property.write(this, currentValue);
#ifdef QT_DEBUG
qDebug() << "QQmlSettings: load" << property.name() << "setting:" << currentValue << "default:" << previousValue;
#endif
}
// ensure that a non-existent setting gets written
// even if the property wouldn't change later
if (!this->m_settings->contains(property.name()))
this->_q_propertyChanged();
// setup change notifications on first load
if (!this->m_initialized && property.hasNotifySignal()) {
static const int propertyChangedIndex = mo->indexOfSlot("_q_propertyChanged()");
int signalIndex = property.notifySignalIndex();
QMetaObject::connect(this, signalIndex, this, propertyChangedIndex);
}
}
}
void MoneroSettings::_q_propertyChanged()
{
// Called on QML property change
const QMetaObject *mo = this->metaObject();
const int offset = mo->propertyOffset();
const int count = mo->propertyCount();
for (int i = offset; i < count; ++i) {
const QMetaProperty &property = mo->property(i);
const QVariant value = readProperty(property);
this->m_changedProperties.insert(property.name(), value);
#ifdef QT_DEBUG
//qDebug() << "QQmlSettings: cache" << property.name() << ":" << value;
#endif
}
if (this->m_timerId != 0)
this->killTimer(this->m_timerId);
this->m_timerId = this->startTimer(settingsWriteDelay);
}
QVariant MoneroSettings::readProperty(const QMetaProperty &property) const
{
QVariant var = property.read(this);
if (var.userType() == qMetaTypeId<QJSValue>())
var = var.value<QJSValue>().toVariant();
return var;
}
void MoneroSettings::init()
{
if (!this->m_initialized) {
this->m_settings = this->m_fileName.isEmpty() ? new QSettings() : new QSettings(this->m_fileName, QSettings::IniFormat);
#ifdef QT_DEBUG
qDebug() << "QQmlSettings: stored at" << this->m_settings->fileName();
#endif
this->load();
this->m_initialized = true;
}
}
void MoneroSettings::reset()
{
if (this->m_initialized && this->m_settings && !this->m_changedProperties.isEmpty())
this->store();
if (this->m_settings)
delete this->m_settings;
}
void MoneroSettings::store()
{
QHash<const char *, QVariant>::const_iterator it = this->m_changedProperties.constBegin();
while (it != this->m_changedProperties.constEnd()) {
this->m_settings->setValue(it.key(), it.value());
#ifdef QT_DEBUG
//qDebug() << "QQmlSettings: store" << it.key() << ":" << it.value();
#endif
++it;
}
this->m_changedProperties.clear();
}
void MoneroSettings::setFileName(const QString &fileName)
{
if (fileName != this->m_fileName) {
this->reset();
this->m_fileName = fileName;
if (this->m_initialized)
this->load();
}
}
QString MoneroSettings::fileName() const
{
return this->m_fileName;
}
void MoneroSettings::timerEvent(QTimerEvent *event)
{
if (event->timerId() == this->m_timerId) {
killTimer(this->m_timerId);
this->m_timerId = 0;
this->store();
}
QObject::timerEvent(event);
}
void MoneroSettings::componentComplete()
{
this->init();
}
void MoneroSettings::classBegin()
{
}
MoneroSettings::MoneroSettings(QObject *parent) :
QObject(parent)
{
}

View File

@@ -1,81 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
****************************************************************************/
// 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.
#ifndef MONEROSETTINGS_H
#define MONEROSETTINGS_H
#include <QtQml/qqmlparserstatus.h>
#include <QGuiApplication>
#include <QClipboard>
#include <QObject>
#include <QDebug>
#include <qsettings.h>
static const int settingsWriteDelay = 500; // ms
class MoneroSettings : public QObject, public QQmlParserStatus
{
Q_OBJECT
Q_INTERFACES(QQmlParserStatus)
Q_PROPERTY(QString fileName READ fileName WRITE setFileName FINAL)
public:
explicit MoneroSettings(QObject *parent = nullptr);
QString fileName() const;
void setFileName(const QString &fileName);
public slots:
void _q_propertyChanged();
protected:
void timerEvent(QTimerEvent *event) override;
void classBegin() override;
void componentComplete() override;
private:
QVariant readProperty(const QMetaProperty &property) const;
void init();
void reset();
void load();
void store();
QHash<const char *, QVariant> m_changedProperties;
QSettings *m_settings = NULL;
QString m_fileName = QString("");
bool m_initialized = false;
int m_timerId = 0;
};
#endif // MONEROSETTINGS_H

View File

@@ -1,100 +0,0 @@
#include <QRegExp>
#include <QMessageBox>
#include <QPixmap>
#include <QTranslator>
#include "TailsOS.h"
#include "utils.h"
bool TailsOS::usePersistence = false;
QString TailsOS::tailsPathData = QString("/live/persistence/TailsData_unlocked/");
bool TailsOS::detect()
{
if (!fileExists("/etc/os-release"))
return false;
QByteArray data = fileOpen("/etc/os-release");
QRegularExpression re("TAILS_PRODUCT_NAME=\"Tails\"");
QRegularExpressionMatch os_match = re.match(data);
bool matched = os_match.hasMatch();
#ifdef QT_DEBUG
if (matched)
qDebug() << "Tails OS detected";
#endif
return matched;
}
bool TailsOS::detectDataPersistence()
{
return QDir(QDir::homePath() + "/Persistent").exists();
}
bool TailsOS::detectDotPersistence()
{
return QDir(tailsPathData + "dotfiles").exists();
}
void TailsOS::showDataPersistenceDisabledWarning()
{
QMessageBox msgBox;
msgBox.setText(QObject::tr("Warning: persistence disabled"));
msgBox.setWindowTitle(QObject::tr("Warning: persistence disabled"));
msgBox.setInformativeText(
QObject::tr("Monero GUI has detected that Tails persistence is "
"currently disabled. Any configurations you make inside "
"the Monero GUI will not be saved."
"\n\n"
"In addition, make sure to not save your wallet on the "
"filesystem, as it will be lost at shutdown."
"\n\n"
"To enable Tails persistence, setup an encrypted volume "
"and restart Tails. To gain a startup menu item, "
"enable the Tails \"dotfiles\" feature."));
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.setIconPixmap(QPixmap(":/images/tails-grey.png"));
msgBox.exec();
}
void TailsOS::askPersistence()
{
QMessageBox msgBox;
msgBox.setWindowTitle(QObject::tr("Monero GUI"));
msgBox.setText(QObject::tr("Use Tails persistence?"));
msgBox.setInformativeText(
QObject::tr("Persist wallet files and configuration on the encrypted volume?"
"\n\n"
"In addition, you can enable Tails dotfiles persistence "
"to gain a start menu entry.\n"));
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
msgBox.setDefaultButton(QMessageBox::Yes);
msgBox.setIconPixmap(QPixmap(":/images/tails-grey.png"));
TailsOS::usePersistence = (msgBox.exec() == QMessageBox::Yes);
}
void TailsOS::persistXdgMime(QString filePath, QString data)
{
QFileInfo file(filePath);
QString tailsPath = tailsPathData + "dotfiles/.local/share/applications/";
// write to persistent volume
#ifdef QT_DEBUG
qDebug() << "Writing xdg mime: " << tailsPath + file.fileName();
#endif
QDir().mkpath(tailsPath); // ensure directory exists
fileWrite(tailsPath + file.fileName(), data);
// write to current session
#ifdef QT_DEBUG
qDebug() << "Writing xdg mime: " << file.filePath();
#endif
QDir().mkpath(file.path()); // ensure directory exists
fileWrite(file.filePath(), data);
}

View File

@@ -1,23 +0,0 @@
#ifndef TAILSOS_H
#define TAILSOS_H
#include <QApplication>
class TailsOS
{
public:
TailsOS();
static bool detect();
static bool detectDataPersistence();
static bool detectDotPersistence();
static void showDataPersistenceDisabledWarning();
static void askPersistence();
static void persistXdgMime(QString filePath, QString data);
static bool usePersistence;
static QString tailsPathData;
};
#endif // TAILSOS_H

View File

@@ -99,8 +99,8 @@ bool IPC::saveCommand(QString cmdString){
return true; return true;
} }
bool IPC::saveCommand(const QUrl &url){ bool IPC::saveCommand(const QUrl &url){;
return this->saveCommand(url.toString()); this->saveCommand(url.toString());
} }
void IPC::handleConnection(){ void IPC::handleConnection(){

View File

@@ -27,23 +27,44 @@
// 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.
#include <QtCore> #include <QtCore>
#include <QtGui> #include <QApplication>
#include <QtMac> #include <QFile>
#include "macoshelper.h" #include <QTextStream>
#import <Foundation/Foundation.h> #include "mime.h"
#import <Cocoa/Cocoa.h> #include "utils.h"
#include <CoreFoundation/CoreFoundation.h>
#include <ApplicationServices/ApplicationServices.h>
#include <Availability.h>
bool MacOSHelper::isCapsLock() void registerXdgMime(QApplication &app){
{ // MacOS handled via Info.plist
#ifdef __MAC_10_12 // Windows handled in the installer by rbrunner7
NSUInteger flags = [NSEvent modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask;
return (flags == NSEventModifierFlagCapsLock); QString xdg = QString(
#else "[Desktop Entry]\n"
NSUInteger flags = [NSEvent modifierFlags] & NSDeviceIndependentModifierFlagsMask; "Name=Monero GUI\n"
return (flags & NSAlphaShiftKeyMask); "GenericName=Monero-GUI\n"
#endif "X-GNOME-FullName=Monero-GUI\n"
"Comment=Monero GUI\n"
"Keywords=Monero;\n"
"Exec=%1 %u\n"
"Terminal=false\n"
"Type=Application\n"
"Icon=monero\n"
"Categories=Network;GNOME;Qt;\n"
"MimeType=x-scheme-handler/monero;x-scheme-handler/moneroseed\n"
"StartupNotify=true\n"
"X-GNOME-Bugzilla-Bugzilla=GNOME\n"
"X-GNOME-UsesNotifications=true\n"
).arg(app.applicationFilePath());
QString appPath = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation);
QString filePath = QString("%1/monero-gui.desktop").arg(appPath);
qDebug() << QString("Writing %1").arg(filePath);
QFile file(filePath);
if(file.open(QIODevice::WriteOnly)){
QTextStream out(&file); out << xdg << endl;
file.close();
}
else
file.close();
} }

View File

@@ -26,15 +26,11 @@
// 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.
#ifndef MACOSHELPER_H #ifndef MIME_H
#define MACOSHELPER_H #define MIME_H
class MacOSHelper #include <QApplication>
{
MacOSHelper() {}
public: void registerXdgMime(QApplication &app);
static bool isCapsLock();
};
#endif //MACOSHELPER_H #endif // MIME_H

View File

@@ -53,7 +53,7 @@ void Prices::getJSON(const QString url) {
void Prices::gotJSON() { void Prices::gotJSON() {
// Check connectivity // Check connectivity
if (!m_reply || m_reply->error() != QNetworkReply::NoError){ if (!m_reply || m_reply->error() != QNetworkReply::NoError){
this->gotError("Problem with reply from server. Check connectivity."); this->gotError();
m_reply->deleteLater(); m_reply->deleteLater();
return; return;
} }
@@ -105,6 +105,6 @@ void Prices::gotError() {
} }
void Prices::gotError(const QString &message) { void Prices::gotError(const QString &message) {
qCritical() << "[Fiat API] Error:" << message; qCritical() << __FUNCTION__ << ": Error: " << message;
emit priceJsonError(message); emit priceJsonError(message);
} }

View File

@@ -27,35 +27,15 @@
// 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.
#include <QtCore> #include <QtCore>
#include <QApplication>
#include "TailsOS.h"
#include "utils.h" #include "utils.h"
bool fileExists(QString path) { bool fileExists(QString path) {
QFileInfo check_file(path); QFileInfo check_file(path);
return check_file.exists() && check_file.isFile(); if (check_file.exists() && check_file.isFile())
}
QByteArray fileOpen(QString path) {
QFile file(path);
if(!file.open(QFile::ReadOnly | QFile::Text))
return QByteArray();
QByteArray data = file.readAll();
file.close();
return data;
}
bool fileWrite(QString path, QString data) {
QFile file(path);
if(file.open(QIODevice::WriteOnly)){
QTextStream out(&file); out << data << endl;
file.close();
return true; return true;
} else
return false;
return false;
} }
QString getAccountName(){ QString getAccountName(){
@@ -67,53 +47,6 @@ QString getAccountName(){
return accountName; return accountName;
} }
#ifdef Q_OS_LINUX
QString xdgMime(QApplication &app){
return QString(
"[Desktop Entry]\n"
"Name=Monero GUI\n"
"GenericName=Monero-GUI\n"
"X-GNOME-FullName=Monero-GUI\n"
"Comment=Monero GUI\n"
"Keywords=Monero;\n"
"Exec=%1 %u\n"
"Terminal=false\n"
"Type=Application\n"
"Icon=monero\n"
"Categories=Network;GNOME;Qt;\n"
"MimeType=x-scheme-handler/monero;x-scheme-handler/moneroseed\n"
"StartupNotify=true\n"
"X-GNOME-Bugzilla-Bugzilla=GNOME\n"
"X-GNOME-UsesNotifications=true\n"
).arg(app.applicationFilePath());
}
void registerXdgMime(QApplication &app){
// Register desktop entry
// - MacOS handled via Info.plist
// - Windows handled in the installer by rbrunner7
// - Linux written to `QStandardPaths::ApplicationsLocation`
// - Tails written to persistent dotfiles
QString mime = xdgMime(app);
QString appPath = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation);
QString filePath = QString("%1/monero-gui.desktop").arg(appPath);
if (TailsOS::detect() && TailsOS::detectDotPersistence() && TailsOS::usePersistence) {
TailsOS::persistXdgMime(filePath, mime);
return;
}
QFileInfo file(filePath);
QDir().mkpath(file.path()); // ensure directory exists
#ifdef QT_DEBUG
qDebug() << "Writing xdg mime: " << filePath;
#endif
fileWrite(filePath, mime);
}
#endif
QString randomUserAgent(){ QString randomUserAgent(){
QStringList urand; QStringList urand;
urand << "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1" urand << "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1"

View File

@@ -31,16 +31,9 @@
#include <QtCore> #include <QtCore>
#include <QRegExp> #include <QRegExp>
#include <QApplication>
bool fileExists(QString path); bool fileExists(QString path);
QByteArray fileOpen(QString path);
bool fileWrite(QString path, QString data);
QString getAccountName(); QString getAccountName();
#ifdef Q_OS_LINUX
QString xdgMime(QApplication &app);
void registerXdgMime(QApplication &app);
#endif
const static QRegExp reURI = QRegExp("^\\w+:\\/\\/([\\w+\\-?\\-_\\-=\\-&]+)"); const static QRegExp reURI = QRegExp("^\\w+:\\/\\/([\\w+\\-?\\-_\\-=\\-&]+)");
QString randomUserAgent(); QString randomUserAgent();

Some files were not shown because too many files have changed in this diff Show More