Compare commits
201 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2f5c47e95f | ||
|
|
34b216e6dc | ||
|
|
d2b9d5690b | ||
|
|
d10f1b5d30 | ||
|
|
fea3bb503f | ||
|
|
d92cc944cb | ||
|
|
f57b2d57cd | ||
|
|
cf0e5a811e | ||
|
|
ea8f51d168 | ||
|
|
e8befc4c67 | ||
|
|
5518771a8b | ||
|
|
47bc0f2a3c | ||
|
|
8bd820b909 | ||
|
|
f948d0e214 | ||
|
|
3a7c9e6c8e | ||
|
|
5a65d28d29 | ||
|
|
e9cdaf4dbe | ||
|
|
17f032ea11 | ||
|
|
ef565e5fa3 | ||
|
|
92f9bec1e7 | ||
|
|
0e3f3c13a1 | ||
|
|
74e12ce71d | ||
|
|
5fe6b48517 | ||
|
|
7f7a39292c | ||
|
|
2e1e227b4c | ||
|
|
ee68bcb6e9 | ||
|
|
025a638082 | ||
|
|
33babc5d85 | ||
|
|
a4c17ac82b | ||
|
|
06ba205320 | ||
|
|
5df14abed2 | ||
|
|
cdad85c0ef | ||
|
|
40e2d2045b | ||
|
|
212c8dd054 | ||
|
|
290582d428 | ||
|
|
582267a923 | ||
|
|
fe3c06c36b | ||
|
|
95d7826163 | ||
|
|
5e2099ad47 | ||
|
|
44280d1e52 | ||
|
|
897d879dad | ||
|
|
631a1c49c8 | ||
|
|
d3b20d2c04 | ||
|
|
c60c9ee69a | ||
|
|
965081c554 | ||
|
|
e6458b58ef | ||
|
|
9207462676 | ||
|
|
ab020358e7 | ||
|
|
135cfbac68 | ||
|
|
3dbf09e7ad | ||
|
|
32257c8fab | ||
|
|
5ecca50977 | ||
|
|
ae2fdc7ab3 | ||
|
|
f72ed257ce | ||
|
|
947e265a1a | ||
|
|
77ff362b58 | ||
|
|
9d40baa3ef | ||
|
|
d3b81cb6f8 | ||
|
|
c87ebf1f31 | ||
|
|
4905341999 | ||
|
|
047dee4eb4 | ||
|
|
dd1046b31f | ||
|
|
2b82a472ae | ||
|
|
8d5ef035d2 | ||
|
|
a3d41a80bf | ||
|
|
413507bba9 | ||
|
|
2ca76ff13c | ||
|
|
a6cd010695 | ||
|
|
411505bff5 | ||
|
|
4f4e879f8d | ||
|
|
448727f4b5 | ||
|
|
ca8138bb46 | ||
|
|
10764b8a68 | ||
|
|
b91afaf5c7 | ||
|
|
31501316c9 | ||
|
|
120a62257f | ||
|
|
a1e416ee83 | ||
|
|
3cf2dc0c04 | ||
|
|
6df9e584b3 | ||
|
|
0d247a9b8a | ||
|
|
bc22de47f9 | ||
|
|
a5b2d5e727 | ||
|
|
2c78f77eb2 | ||
|
|
738e802f3c | ||
|
|
8dab0755d3 | ||
|
|
5f81b573c0 | ||
|
|
a267712d10 | ||
|
|
0abaae073d | ||
|
|
a6791561d6 | ||
|
|
3ca2473239 | ||
|
|
779cc3e24d | ||
|
|
cfd2139310 | ||
|
|
4c05bff21e | ||
|
|
5392dd7ed0 | ||
|
|
cb9cb6eb09 | ||
|
|
3a33ddeecd | ||
|
|
a83910d7de | ||
|
|
336ed9d6e5 | ||
|
|
346e942e93 | ||
|
|
13a5be7306 | ||
|
|
bdceff6380 | ||
|
|
17c61f897a | ||
|
|
9a58e88ec6 | ||
|
|
355cccaa64 | ||
|
|
29580de2c7 | ||
|
|
67e08da918 | ||
|
|
e660b2d169 | ||
|
|
40bdf692d1 | ||
|
|
562c46660a | ||
|
|
0724dd0043 | ||
|
|
c0932a1bd5 | ||
|
|
d7a65fafad | ||
|
|
239e27c1b5 | ||
|
|
1ca10373a3 | ||
|
|
ac6687f6ff | ||
|
|
b616e1c8f6 | ||
|
|
1ec22b3d0c | ||
|
|
a01ffc6e1a | ||
|
|
e1bbc1e525 | ||
|
|
049cef9ce3 | ||
|
|
18f7a6a694 | ||
|
|
30a3abedbe | ||
|
|
2f5c926c82 | ||
|
|
55b4425c5d | ||
|
|
dc49d7af38 | ||
|
|
e01c2e903a | ||
|
|
886be81af2 | ||
|
|
671ddf5bef | ||
|
|
5f8cb04fee | ||
|
|
3f06560c51 | ||
|
|
f666e6f42e | ||
|
|
e546ce83b4 | ||
|
|
059a2d754e | ||
|
|
1e64ebe17a | ||
|
|
8abf8f844f | ||
|
|
01740a253d | ||
|
|
0461a28701 | ||
|
|
a3b1590286 | ||
|
|
b5cbb8b990 | ||
|
|
ff23a5bf1e | ||
|
|
afe2b14430 | ||
|
|
d4a6826d13 | ||
|
|
8d17018019 | ||
|
|
a65222d057 | ||
|
|
25e56ee8fb | ||
|
|
40c3e38f5a | ||
|
|
f810c56100 | ||
|
|
95b3bb955c | ||
|
|
8db07974e2 | ||
|
|
6c25650bbd | ||
|
|
4775fd74b8 | ||
|
|
f20ab12cf3 | ||
|
|
e6642c4338 | ||
|
|
5b81a1a9d6 | ||
|
|
7e40a810eb | ||
|
|
e7653d0497 | ||
|
|
8f7d2b592a | ||
|
|
7480f9b559 | ||
|
|
ba33649d7e | ||
|
|
705439c78b | ||
|
|
cddba56848 | ||
|
|
39fe5478b9 | ||
|
|
cb3c310eb8 | ||
|
|
c426f1eb83 | ||
|
|
beb94783c6 | ||
|
|
0b61328971 | ||
|
|
b96004a101 | ||
|
|
d2e7358db7 | ||
|
|
cfec9dde96 | ||
|
|
e04d563eb4 | ||
|
|
96c99b250e | ||
|
|
4370733b2b | ||
|
|
cac7662558 | ||
|
|
0abd21b434 | ||
|
|
0d29ea33d8 | ||
|
|
3a9f0e1100 | ||
|
|
d113bf1a66 | ||
|
|
2d72f55e57 | ||
|
|
4b0d1dcfbf | ||
|
|
35a0f25b57 | ||
|
|
702b654f09 | ||
|
|
f6de660e0e | ||
|
|
b3402b3d4e | ||
|
|
5b411b471e | ||
|
|
79dcb92d18 | ||
|
|
8bbc2e87bc | ||
|
|
c10ea20f83 | ||
|
|
b4231a758c | ||
|
|
59550ec673 | ||
|
|
6baa96360f | ||
|
|
14619b9437 | ||
|
|
817115fa47 | ||
|
|
5f5f2103c0 | ||
|
|
84865cdead | ||
|
|
c34a2b43fc | ||
|
|
ab9e31e7cc | ||
|
|
e1b4bcb2ef | ||
|
|
c4b3fbae1d | ||
|
|
1b5796a0ee | ||
|
|
9ab2922eb2 | ||
|
|
ab47b4a783 |
30
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
name: GUI build
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build-macos:
|
||||
|
||||
runs-on: macOS-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: update brew and install dependencies
|
||||
run: brew update && brew install boost hidapi zmq libpgm unbound libsodium miniupnpc ldns expat doxygen graphviz libunwind-headers protobuf qt5
|
||||
- name: build
|
||||
run: export PATH=$PATH:/usr/local/opt/qt/bin && ./build.sh
|
||||
|
||||
build-ubuntu:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: update apt
|
||||
run: sudo apt update
|
||||
- name: install monero dependencies
|
||||
run: sudo apt -y 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
|
||||
- name: install monero gui dependencies
|
||||
run: sudo apt -y install qtbase5-dev qt5-default qtdeclarative5-dev qml-module-qtquick-controls qml-module-qtquick-controls2 qml-module-qtquick-dialogs qml-module-qtquick-xmllistmodel qml-module-qt-labs-settings qml-module-qt-labs-folderlistmodel qttools5-dev-tools qml-module-qtquick-templates2 libqt5svg5-dev
|
||||
- name: build
|
||||
run: ./build.sh
|
||||
19
.gitignore
vendored
@@ -13,3 +13,22 @@ monero-wallet-gui_plugin_import.cpp
|
||||
monero-wallet-gui_qml_plugin_import.cpp
|
||||
*.qmlc
|
||||
*.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~
|
||||
|
||||
364
LeftPanel.qml
@@ -40,17 +40,17 @@ import "components/effects/" as MoneroEffects
|
||||
Rectangle {
|
||||
id: panel
|
||||
|
||||
property alias unlockedBalanceText: unlockedBalanceText.text
|
||||
property alias unlockedBalanceVisible: unlockedBalanceText.visible
|
||||
property alias unlockedBalanceLabelVisible: unlockedBalanceLabel.visible
|
||||
property alias balanceLabelText: balanceLabel.text
|
||||
property alias balanceText: balanceText.text
|
||||
property alias balanceTextFiat: balanceTextFiat.text
|
||||
property alias unlockedBalanceTextFiat: unlockedBalanceTextFiat.text
|
||||
property int currentAccountIndex: 0
|
||||
property string currentAccountLabel: "Primary account"
|
||||
property string balanceString: "?.??"
|
||||
property string balanceUnlockedString: "?.??"
|
||||
property string balanceFiatString: "?.??"
|
||||
property string minutesToUnlock: ""
|
||||
property bool isSyncing: false
|
||||
property alias networkStatus : networkStatus
|
||||
property alias progressBar : progressBar
|
||||
property alias daemonProgressBar : daemonProgressBar
|
||||
property alias minutesToUnlockTxt: unlockedBalanceLabel.text
|
||||
|
||||
property int titleBarHeight: 50
|
||||
property string copyValue: ""
|
||||
Clipboard { id: clipboard }
|
||||
@@ -84,7 +84,7 @@ Rectangle {
|
||||
menuColumn.previousButton.checked = true
|
||||
}
|
||||
|
||||
width: (isMobile)? appWindow.width : 300
|
||||
width: 300
|
||||
color: "transparent"
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.top: parent.top
|
||||
@@ -108,19 +108,18 @@ Rectangle {
|
||||
visible: true
|
||||
z: 2
|
||||
id: column1
|
||||
height: 210
|
||||
height: 175
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: (persistentSettings.customDecorations)? 50 : 0
|
||||
|
||||
RowLayout {
|
||||
Item {
|
||||
Item {
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 20
|
||||
anchors.leftMargin: 20
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
height: 490
|
||||
width: 260
|
||||
|
||||
@@ -128,9 +127,9 @@ Rectangle {
|
||||
id: card
|
||||
visible: !isOpenGL || MoneroComponents.Style.blackTheme
|
||||
width: 260
|
||||
height: 170
|
||||
height: 135
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: "qrc:///images/card-background.png"
|
||||
source: MoneroComponents.Style.blackTheme ? "qrc:///images/card-background-black.png" : "qrc:///images/card-background-white.png"
|
||||
}
|
||||
|
||||
DropShadow {
|
||||
@@ -172,57 +171,6 @@ Rectangle {
|
||||
color: "#ff9323"
|
||||
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 {
|
||||
@@ -230,181 +178,155 @@ Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 20
|
||||
anchors.leftMargin: 20
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
height: 490
|
||||
width: 50
|
||||
|
||||
MoneroComponents.TextPlain {
|
||||
visible: !(persistentSettings.fiatPriceToggle && persistentSettings.fiatPriceEnabled)
|
||||
id: balanceText
|
||||
themeTransition: false
|
||||
MoneroComponents.Label {
|
||||
fontSize: 12
|
||||
id: accountIndex
|
||||
text: qsTr("Account") + " #" + currentAccountIndex
|
||||
color: MoneroComponents.Style.blackTheme ? "white" : "black"
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 20
|
||||
anchors.leftMargin: 60
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 76
|
||||
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 = 22;
|
||||
if(digits > 2) {
|
||||
return defaultSize - 1.1*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 {
|
||||
visible: !balanceText.visible
|
||||
id: balanceTextFiat
|
||||
anchors.topMargin: 23
|
||||
themeTransition: false
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 20
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 76
|
||||
font.family: "Arial"
|
||||
color: "#FFFFFF"
|
||||
text: "N/A"
|
||||
font.pixelSize: balanceText.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.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
|
||||
MouseArea{
|
||||
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)
|
||||
}
|
||||
onClicked: appWindow.showPageRequest("Account")
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.Label {
|
||||
id: unlockedBalanceLabel
|
||||
visible: true
|
||||
text: qsTr("Unlocked balance") + translationManager.emptyString
|
||||
color: "white"
|
||||
fontSize: 14
|
||||
fontSize: 16
|
||||
id: accountLabel
|
||||
textWidth: 170
|
||||
text: currentAccountLabel
|
||||
color: MoneroComponents.Style.blackTheme ? "white" : "black"
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 20
|
||||
anchors.leftMargin: 60
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 110
|
||||
anchors.topMargin: 36
|
||||
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
|
||||
|
||||
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 {
|
||||
id: currencyLabel
|
||||
font.pixelSize: 16
|
||||
text: {
|
||||
if (persistentSettings.fiatPriceEnabled && persistentSettings.fiatPriceToggle) {
|
||||
return appWindow.fiatApiCurrencySymbol();
|
||||
} else {
|
||||
return "XMR"
|
||||
}
|
||||
}
|
||||
color: MoneroComponents.Style.blackTheme ? "white" : "black"
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 20
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 100
|
||||
themeTransition: false
|
||||
|
||||
MouseArea {
|
||||
hoverEnabled: true
|
||||
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: {
|
||||
var defaultSize = 29;
|
||||
var digits = (balancePart1.text.length - 1)
|
||||
if (digits > 2 && !(persistentSettings.fiatPriceEnabled && persistentSettings.fiatPriceToggle)) {
|
||||
return defaultSize - 1.1 * digits
|
||||
} else {
|
||||
return defaultSize
|
||||
}
|
||||
}
|
||||
MouseArea {
|
||||
id: balancePart1MouseArea
|
||||
hoverEnabled: true
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onEntered: {
|
||||
balancePart1.color = MoneroComponents.Style.orange
|
||||
balancePart2.color = MoneroComponents.Style.orange
|
||||
}
|
||||
onExited: {
|
||||
balancePart1.color = Qt.binding(function() { return MoneroComponents.Style.blackTheme ? "white" : "black" })
|
||||
balancePart2.color = Qt.binding(function() { return MoneroComponents.Style.blackTheme ? "white" : "black" })
|
||||
}
|
||||
onClicked: {
|
||||
console.log("Copied to clipboard");
|
||||
clipboard.setText(balancePart1.text + balancePart2.text);
|
||||
appWindow.showStatusMessage(qsTr("Copied to clipboard"),3)
|
||||
}
|
||||
}
|
||||
}
|
||||
MoneroComponents.TextPlain {
|
||||
id: balancePart2
|
||||
themeTransition: false
|
||||
anchors.left: balancePart1.right
|
||||
anchors.leftMargin: 2
|
||||
anchors.baseline: currencyLabel.baseline
|
||||
color: MoneroComponents.Style.blackTheme ? "white" : "black"
|
||||
text: {
|
||||
if (persistentSettings.fiatPriceEnabled && persistentSettings.fiatPriceToggle) {
|
||||
return balanceFiatString.split('.')[1]
|
||||
} else {
|
||||
return balanceString.split('.')[1]
|
||||
}
|
||||
}
|
||||
font.pixelSize: 16
|
||||
MouseArea {
|
||||
hoverEnabled: true
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onEntered: balancePart1MouseArea.entered()
|
||||
onExited: balancePart1MouseArea.exited()
|
||||
onClicked: balancePart1MouseArea.clicked(mouse)
|
||||
}
|
||||
}
|
||||
|
||||
Item { //separator
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
@@ -420,7 +342,7 @@ Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.top: (isMobile)? parent.top : column1.bottom
|
||||
anchors.top: column1.bottom
|
||||
color: "transparent"
|
||||
|
||||
Flickable {
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <QDebug>
|
||||
|
||||
#include "Logger.h"
|
||||
#include "src/qt/TailsOS.h"
|
||||
#include "wallet/api/wallet2_api.h"
|
||||
|
||||
// default log path by OS (should be writable)
|
||||
@@ -66,6 +67,9 @@ const QString getLogPath(const QString logPath)
|
||||
{
|
||||
const QFileInfo fi(logPath);
|
||||
|
||||
if(TailsOS::detect() && TailsOS::usePersistence)
|
||||
return QDir::homePath() + "/Persistent/Monero/logs/" + defaultLogName;
|
||||
|
||||
if(!logPath.isEmpty() && !fi.isDir())
|
||||
return fi.absoluteFilePath();
|
||||
else {
|
||||
|
||||
@@ -46,11 +46,6 @@ Rectangle {
|
||||
|
||||
property Item currentView
|
||||
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 alias contentHeight: mainFlickable.contentHeight
|
||||
property alias flickable: mainFlickable
|
||||
@@ -209,13 +204,13 @@ Rectangle {
|
||||
clip: true
|
||||
|
||||
ScrollBar.vertical: ScrollBar {
|
||||
parent: mainFlickable.parent
|
||||
parent: root
|
||||
anchors.left: parent.right
|
||||
anchors.leftMargin: 3
|
||||
anchors.leftMargin: -14 // 10 margin + 4 scrollbar width
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 4
|
||||
anchors.topMargin: persistentSettings.customDecorations ? 60 : 10
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: persistentSettings.customDecorations ? 4 : 0
|
||||
anchors.bottomMargin: persistentSettings.customDecorations ? 15 : 10
|
||||
}
|
||||
|
||||
onFlickingChanged: {
|
||||
|
||||
15
README.md
@@ -9,7 +9,7 @@ Copyright (c) 2014-2019, The Monero Project
|
||||
- Mail: [dev@getmonero.org](mailto:dev@getmonero.org)
|
||||
- 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)
|
||||
- Translation platform (Pootle): [translate.getmonero.org](https://translate.getmonero.org)
|
||||
- Translation platform (Weblate): [translate.getmonero.org](https://translate.getmonero.org)
|
||||
|
||||
## Vulnerability response
|
||||
|
||||
@@ -75,6 +75,8 @@ Packaging for your favorite distribution would be a welcome contribution!
|
||||
|
||||
## Compiling the Monero GUI from source
|
||||
|
||||
*Note*: Qt 5.9.7 is the minimum version required to build the GUI.
|
||||
|
||||
### On Linux:
|
||||
|
||||
(Tested on Ubuntu 17.10 x64, Ubuntu 18.04 x64 and Gentoo x64)
|
||||
@@ -83,7 +85,7 @@ Packaging for your favorite distribution would be a welcome contribution!
|
||||
|
||||
- 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`
|
||||
`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`
|
||||
|
||||
- For Gentoo
|
||||
|
||||
@@ -91,11 +93,11 @@ Packaging for your favorite distribution would be a welcome contribution!
|
||||
|
||||
- For Fedora
|
||||
|
||||
`sudo dnf install make automake cmake gcc-c++ boost-devel miniupnpc-devel graphviz doxygen unbound-devel libunwind-devel pkgconfig openssl-devel libcurl-devel hidapi-devel libusb-devel`
|
||||
`sudo dnf install make automake cmake gcc-c++ boost-devel miniupnpc-devel graphviz doxygen unbound-devel libunwind-devel pkgconfig openssl-devel libcurl-devel hidapi-devel libusb-devel zeromq-devel`
|
||||
|
||||
2. Install Qt:
|
||||
|
||||
*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.
|
||||
*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.
|
||||
|
||||
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.
|
||||
|
||||
@@ -165,9 +167,8 @@ The executable can be found in the build/release/bin folder.
|
||||
|
||||
5. Add the Qt bin directory to your path
|
||||
|
||||
Example: `export PATH=$PATH:$HOME/Qt/5.9.7/clang_64/bin`
|
||||
|
||||
This is the directory where Qt 5.x is installed on **your** system
|
||||
- Example for Qt: `export PATH=$PATH:$HOME/Qt/5.9.7/clang_64/bin`
|
||||
- Example for Homebrew: `export PATH=$PATH:/usr/local/opt/qt/bin`
|
||||
|
||||
6. Grab an up-to-date copy of the monero-gui repository
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ Item {
|
||||
property string uncheckedIcon
|
||||
property int imgWidth: 13
|
||||
property int imgHeight: 13
|
||||
property bool toggleOnClick: true
|
||||
property bool checked: false
|
||||
property alias background: backgroundRect.color
|
||||
property bool border: true
|
||||
@@ -51,14 +52,16 @@ Item {
|
||||
width: checkBoxLayout.width
|
||||
|
||||
function toggle(){
|
||||
checkBox.checked = !checkBox.checked
|
||||
if (checkBox.toggleOnClick) {
|
||||
checkBox.checked = !checkBox.checked
|
||||
}
|
||||
checkBox.clicked()
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: checkBoxLayout
|
||||
layoutDirection: iconOnTheLeft ? Qt.LeftToRight : Qt.RightToLeft
|
||||
spacing: (!isMobile ? 10 : 8)
|
||||
spacing: 10
|
||||
|
||||
Item {
|
||||
id: checkMark
|
||||
|
||||
40
components/ContextMenu.qml
Normal file
@@ -0,0 +1,40 @@
|
||||
import QtQuick 2.9
|
||||
import QtQuick.Controls 2.2
|
||||
|
||||
import FontAwesome 1.0
|
||||
import "../components" as MoneroComponents
|
||||
|
||||
MouseArea {
|
||||
signal paste()
|
||||
|
||||
id: root
|
||||
acceptedButtons: Qt.RightButton
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
if (mouse.button === Qt.RightButton)
|
||||
contextMenu.open()
|
||||
}
|
||||
|
||||
Menu {
|
||||
id: contextMenu
|
||||
|
||||
background: Rectangle {
|
||||
border.color: MoneroComponents.Style.buttonBackgroundColorDisabledHover
|
||||
border.width: 1
|
||||
radius: 2
|
||||
color: MoneroComponents.Style.buttonBackgroundColorDisabled
|
||||
}
|
||||
|
||||
padding: 1
|
||||
width: 100
|
||||
x: root.mouseX
|
||||
y: root.mouseY
|
||||
|
||||
MoneroComponents.ContextMenuItem {
|
||||
enabled: root.parent.canPaste === true
|
||||
glyphIcon: FontAwesome.paste
|
||||
onTriggered: root.paste()
|
||||
text: qsTr("Paste") + translationManager.emptyString
|
||||
}
|
||||
}
|
||||
}
|
||||
52
components/ContextMenuItem.qml
Normal file
@@ -0,0 +1,52 @@
|
||||
import QtQuick 2.9
|
||||
import QtQuick.Controls 2.2
|
||||
import QtQuick.Layouts 1.1
|
||||
|
||||
import FontAwesome 1.0
|
||||
import "../components" as MoneroComponents
|
||||
|
||||
MenuItem {
|
||||
id: menuItem
|
||||
|
||||
property bool glyphIconSolid: true
|
||||
property alias glyphIcon: glyphIcon.text
|
||||
|
||||
background: Rectangle {
|
||||
color: MoneroComponents.Style.buttonBackgroundColorDisabledHover
|
||||
opacity: mouse.containsMouse ? 1 : 0
|
||||
|
||||
MouseArea {
|
||||
id: mouse
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: menuItem.triggered()
|
||||
visible: menuItem.enabled
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 10
|
||||
anchors.rightMargin: 10
|
||||
opacity: menuItem.enabled ? 1 : 0.4
|
||||
spacing: 8
|
||||
|
||||
Text {
|
||||
id: glyphIcon
|
||||
|
||||
color: MoneroComponents.Style.buttonTextColor
|
||||
font.family: glyphIconSolid ? FontAwesome.fontFamilySolid : FontAwesome.fontFamily
|
||||
font.pixelSize: 14
|
||||
font.styleName: glyphIconSolid ? "Solid" : "Regular"
|
||||
}
|
||||
|
||||
Text {
|
||||
color: MoneroComponents.Style.buttonTextColor
|
||||
font.family: MoneroComponents.Style.fontRegular.name
|
||||
font.pixelSize: 14
|
||||
Layout.fillWidth: true
|
||||
text: menuItem.text
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -178,7 +178,11 @@ Window {
|
||||
onAccepted: {
|
||||
if(text.length > 0) {
|
||||
textArea.logCommand(">>> " + text)
|
||||
daemonManager.sendCommand(text, currentWallet.nettype);
|
||||
daemonManager.sendCommandAsync(text.split(" "), currentWallet.nettype, function(result) {
|
||||
if (!result) {
|
||||
appWindow.showStatusMessage(qsTr("Failed to send command"), 3);
|
||||
}
|
||||
});
|
||||
}
|
||||
text = ""
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import QtQuick 2.9
|
||||
import "../components" as MoneroComponents
|
||||
|
||||
TextField {
|
||||
id: textField
|
||||
font.family: MoneroComponents.Style.fontRegular.name
|
||||
font.pixelSize: 18
|
||||
font.bold: true
|
||||
@@ -44,4 +45,11 @@ TextField {
|
||||
background: Rectangle {
|
||||
color: "transparent"
|
||||
}
|
||||
|
||||
MoneroComponents.ContextMenu {
|
||||
onPaste: {
|
||||
textField.clear();
|
||||
textField.paste();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ Item {
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
}
|
||||
|
||||
TextField {
|
||||
MoneroComponents.Input {
|
||||
id : input
|
||||
focus: true
|
||||
Layout.topMargin: 6
|
||||
|
||||
@@ -57,6 +57,10 @@ TextArea {
|
||||
onTextChanged: {
|
||||
if(addressValidation){
|
||||
// js replacement for `RegExpValidator { regExp: /[0-9A-Fa-f]{95}/g }`
|
||||
if (textArea.text.startsWith("monero:")) {
|
||||
error = false;
|
||||
return;
|
||||
}
|
||||
textArea.text = textArea.text.replace(/[^a-z0-9.@\-]/gi,'');
|
||||
var address_ok = TxUtils.checkAddress(textArea.text, appWindow.persistentSettings.nettype) || TxUtils.isValidOpenAliasAddress(textArea.text);
|
||||
if(!address_ok) error = true;
|
||||
@@ -64,4 +68,11 @@ TextArea {
|
||||
TextArea.cursorPosition = textArea.text.length;
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.ContextMenu {
|
||||
onPaste: {
|
||||
textArea.clear();
|
||||
textArea.paste();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ Item {
|
||||
property alias horizontalAlignment: label.horizontalAlignment
|
||||
property alias elide: label.elide
|
||||
property alias textWidth: label.width
|
||||
property alias styleName: label.font.styleName
|
||||
property alias themeTransition: label.themeTransition
|
||||
signal linkActivated()
|
||||
height: label.height
|
||||
|
||||
@@ -34,8 +34,6 @@ import "../components/effects/" as MoneroEffects
|
||||
Label {
|
||||
id: item
|
||||
fontSize: 18
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
Rectangle {
|
||||
anchors.top: item.bottom
|
||||
|
||||
@@ -53,6 +53,8 @@ Item {
|
||||
property alias inlineButtonText: inlineButtonId.text
|
||||
property alias inlineIcon: inlineIcon.visible
|
||||
property bool copyButton: false
|
||||
property alias copyButtonText: copyButtonId.text
|
||||
property alias copyButtonEnabled: copyButtonId.enabled
|
||||
|
||||
property bool borderDisabled: false
|
||||
property string borderColor: {
|
||||
|
||||
@@ -80,9 +80,6 @@ ColumnLayout {
|
||||
property alias readOnly: input.readOnly
|
||||
property bool copyButton: false
|
||||
property bool pasteButton: false
|
||||
property var onPaste: function(clipboardText) {
|
||||
item.text = clipboardText;
|
||||
}
|
||||
property bool showingHeader: labelText != "" || copyButton || pasteButton
|
||||
property var wrapMode: Text.NoWrap
|
||||
property alias addressValidation: input.addressValidation
|
||||
@@ -146,7 +143,10 @@ ColumnLayout {
|
||||
|
||||
MoneroComponents.LabelButton {
|
||||
id: pasteButtonId
|
||||
onClicked: item.onPaste(clipboard.text())
|
||||
onClicked: {
|
||||
input.clear();
|
||||
input.paste();
|
||||
}
|
||||
text: qsTr("Paste") + translationManager.emptyString
|
||||
visible: pasteButton
|
||||
}
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
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"
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,7 @@
|
||||
import QtQuick 2.9
|
||||
import QtQuick.Layouts 1.1
|
||||
|
||||
import FontAwesome 1.0
|
||||
import moneroComponents.Wallet 1.0
|
||||
import "../components" as MoneroComponents
|
||||
|
||||
@@ -88,6 +89,7 @@ Rectangle {
|
||||
}
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
visible: appWindow.walletMode >= 2
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if(!appWindow.isMining) {
|
||||
@@ -133,6 +135,7 @@ Rectangle {
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
visible: appWindow.walletMode >= 2
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if(!appWindow.isMining) {
|
||||
@@ -144,6 +147,50 @@ 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,287 +0,0 @@
|
||||
// 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,321 +0,0 @@
|
||||
// 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,34 +44,63 @@ Item {
|
||||
z: parent.z + 2
|
||||
|
||||
property bool isHidden: true
|
||||
property alias password: passwordInput.text
|
||||
property alias password: passwordInput1.text
|
||||
property string walletName
|
||||
property string errorText
|
||||
property bool shiftIsPressed: false
|
||||
property bool isCapsLocksActive: false
|
||||
property bool backspaceIsPressed: false
|
||||
property bool passwordDialogMode
|
||||
property bool passphraseDialogMode
|
||||
property bool newPasswordDialogMode
|
||||
|
||||
// same signals as Dialog has
|
||||
signal accepted()
|
||||
signal acceptedNewPassword()
|
||||
signal acceptedPassphrase()
|
||||
signal rejected()
|
||||
signal rejectedNewPassword()
|
||||
signal rejectedPassphrase()
|
||||
signal closeCallback()
|
||||
|
||||
function open(walletName, errorText) {
|
||||
function _openInit(walletName, errorText) {
|
||||
isHidden = true
|
||||
passwordInput.echoMode = TextInput.Password
|
||||
passwordInput.text = ""
|
||||
passwordInput.forceActiveFocus();
|
||||
capsLockTextLabel.visible = oshelper.isCapsLock();
|
||||
passwordInput1.echoMode = TextInput.Password
|
||||
passwordInput2.echoMode = TextInput.Password
|
||||
passwordInput1.text = ""
|
||||
passwordInput2.text = ""
|
||||
passwordInput1.forceActiveFocus();
|
||||
inactiveOverlay.visible = true // draw appwindow inactive
|
||||
root.walletName = walletName ? walletName : ""
|
||||
errorTextLabel.text = errorText ? errorText : "";
|
||||
leftPanel.enabled = false
|
||||
middlePanel.enabled = false
|
||||
wizard.enabled = false
|
||||
titleBar.state = "essentials"
|
||||
root.visible = true;
|
||||
appWindow.hideBalanceForced = true;
|
||||
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) {
|
||||
open(root.walletName, errorText);
|
||||
}
|
||||
@@ -80,6 +109,7 @@ Item {
|
||||
inactiveOverlay.visible = false
|
||||
leftPanel.enabled = true
|
||||
middlePanel.enabled = true
|
||||
wizard.enabled = true
|
||||
titleBar.state = "default"
|
||||
|
||||
root.visible = false;
|
||||
@@ -88,6 +118,12 @@ Item {
|
||||
closeCallback();
|
||||
}
|
||||
|
||||
function toggleIsHidden() {
|
||||
passwordInput1.echoMode = isHidden ? TextInput.Normal : TextInput.Password;
|
||||
passwordInput2.echoMode = isHidden ? TextInput.Normal : TextInput.Password;
|
||||
isHidden = !isHidden;
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
z: inactiveOverlay.z + 1
|
||||
id: mainLayout
|
||||
@@ -102,7 +138,14 @@ Item {
|
||||
Layout.maximumWidth: 400
|
||||
|
||||
Label {
|
||||
text: (root.walletName.length > 0 ? qsTr("Please enter wallet password for: ") + root.walletName : qsTr("Please enter wallet password")) + translationManager.emptyString
|
||||
text: {
|
||||
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
|
||||
|
||||
font.pixelSize: 16
|
||||
@@ -111,19 +154,41 @@ Item {
|
||||
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 {
|
||||
id: errorTextLabel
|
||||
visible: root.errorText || text !== ""
|
||||
|
||||
color: MoneroComponents.Style.errorColor
|
||||
font.pixelSize: 16
|
||||
font.family: MoneroComponents.Style.fontLight.name
|
||||
font.family: MoneroComponents.Style.fontLight.name
|
||||
Layout.fillWidth: true
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
|
||||
TextField {
|
||||
id : passwordInput
|
||||
Label {
|
||||
id: capsLockTextLabel
|
||||
visible: false
|
||||
color: MoneroComponents.Style.errorColor
|
||||
font.pixelSize: 16
|
||||
font.family: MoneroComponents.Style.fontLight.name
|
||||
Layout.fillWidth: true
|
||||
wrapMode: Text.Wrap
|
||||
text: qsTr("CAPSLOCKS IS ON.") + translationManager.emptyString;
|
||||
}
|
||||
|
||||
MoneroComponents.Input {
|
||||
id: passwordInput1
|
||||
Layout.topMargin: 6
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: TextInput.AlignLeft
|
||||
@@ -131,24 +196,20 @@ Item {
|
||||
font.family: MoneroComponents.Style.fontLight.name
|
||||
font.pixelSize: 24
|
||||
echoMode: TextInput.Password
|
||||
KeyNavigation.tab: okButton
|
||||
KeyNavigation.tab: {
|
||||
if (passwordDialogMode) {
|
||||
return okButton
|
||||
} else {
|
||||
return passwordInput2
|
||||
}
|
||||
}
|
||||
bottomPadding: 10
|
||||
leftPadding: 10
|
||||
topPadding: 10
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
selectionColor: MoneroComponents.Style.textSelectionColor
|
||||
selectedTextColor: MoneroComponents.Style.textSelectedColor
|
||||
|
||||
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 = "";
|
||||
}
|
||||
}
|
||||
onTextChanged: capsLockTextLabel.visible = oshelper.isCapsLock();
|
||||
|
||||
background: Rectangle {
|
||||
radius: 2
|
||||
@@ -177,8 +238,7 @@ Item {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
passwordInput.echoMode = isHidden ? TextInput.Normal : TextInput.Password;
|
||||
isHidden = !isHidden;
|
||||
toggleIsHidden();
|
||||
}
|
||||
onEntered: {
|
||||
parent.opacity = 0.9
|
||||
@@ -195,28 +255,129 @@ Item {
|
||||
Keys.enabled: root.visible
|
||||
Keys.onReturnPressed: {
|
||||
root.close()
|
||||
root.accepted()
|
||||
if (passwordDialogMode) {
|
||||
root.accepted()
|
||||
} else if (newPasswordDialogMode) {
|
||||
root.acceptedNewPassword()
|
||||
} else if (passphraseDialogMode) {
|
||||
root.acceptedPassphrase()
|
||||
}
|
||||
}
|
||||
Keys.onEscapePressed: {
|
||||
root.close()
|
||||
root.rejected()
|
||||
}
|
||||
Keys.onPressed: {
|
||||
if(event.key === Qt.Key_Shift){
|
||||
shiftIsPressed = true;
|
||||
}
|
||||
if(event.key === Qt.Key_Backspace){
|
||||
backspaceIsPressed = true;
|
||||
if (passwordDialogMode) {
|
||||
root.rejected()
|
||||
} else if (newPasswordDialogMode) {
|
||||
root.rejectedNewPassword()
|
||||
} else if (passphraseDialogMode) {
|
||||
root.rejectedPassphrase()
|
||||
}
|
||||
}
|
||||
Keys.onReleased: {
|
||||
if(event.key === Qt.Key_Shift){
|
||||
shiftIsPressed = false;
|
||||
}
|
||||
if(event.key === Qt.Key_Backspace){
|
||||
backspaceIsPressed =false;
|
||||
}
|
||||
|
||||
// padding
|
||||
Rectangle {
|
||||
visible: !passwordDialogMode
|
||||
Layout.fillWidth: true
|
||||
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
|
||||
}
|
||||
|
||||
MoneroComponents.Input {
|
||||
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
|
||||
@@ -229,26 +390,38 @@ Item {
|
||||
MoneroComponents.StandardButton {
|
||||
id: cancelButton
|
||||
small: true
|
||||
text: root.walletName.length > 0 ? qsTr("Change wallet") + translationManager.emptyString : qsTr("Cancel") + translationManager.emptyString
|
||||
KeyNavigation.tab: passwordInput
|
||||
text: qsTr("Cancel") + translationManager.emptyString
|
||||
KeyNavigation.tab: passwordInput1
|
||||
onClicked: {
|
||||
root.close()
|
||||
root.rejected()
|
||||
if (passwordDialogMode) {
|
||||
root.rejected()
|
||||
} else if (newPasswordDialogMode) {
|
||||
root.rejectedNewPassword()
|
||||
} else if (passphraseDialogMode) {
|
||||
root.rejectedPassphrase()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.StandardButton {
|
||||
id: okButton
|
||||
small: true
|
||||
text: qsTr("Continue") + translationManager.emptyString
|
||||
text: qsTr("Ok") + translationManager.emptyString
|
||||
KeyNavigation.tab: cancelButton
|
||||
enabled: (passwordDialogMode == true) ? true : passwordInput1.text === passwordInput2.text
|
||||
onClicked: {
|
||||
root.close()
|
||||
root.accepted()
|
||||
if (passwordDialogMode) {
|
||||
root.accepted()
|
||||
} else if (newPasswordDialogMode) {
|
||||
root.acceptedNewPassword()
|
||||
} else if (passphraseDialogMode) {
|
||||
root.acceptedPassphrase()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ Item {
|
||||
|
||||
MoneroComponents.TextPlain {
|
||||
id: label
|
||||
Layout.leftMargin: (!isMobile ? 10 : 8)
|
||||
Layout.leftMargin: 10
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
font.family: MoneroComponents.Style.fontRegular.name
|
||||
font.pixelSize: radioButton.fontSize
|
||||
|
||||
@@ -35,7 +35,7 @@ import "../js/Utils.js" as Utils
|
||||
import "../components" as MoneroComponents
|
||||
|
||||
GridLayout {
|
||||
columns: (isMobile) ? 1 : 2
|
||||
columns: 2
|
||||
columnSpacing: 32
|
||||
id: root
|
||||
property alias daemonAddrText: daemonAddr.text
|
||||
|
||||
65
components/SettingsListItem.qml
Normal file
@@ -0,0 +1,65 @@
|
||||
import QtQuick 2.9
|
||||
import QtQuick.Layouts 1.1
|
||||
|
||||
import "../components" as MoneroComponents
|
||||
|
||||
ColumnLayout {
|
||||
property alias buttonText: button.text
|
||||
property alias description: description.text
|
||||
property alias title: title.text
|
||||
signal clicked()
|
||||
|
||||
id: settingsListItem
|
||||
Layout.fillWidth: true
|
||||
spacing: 0
|
||||
|
||||
Rectangle {
|
||||
// divider
|
||||
Layout.preferredHeight: 1
|
||||
Layout.fillWidth: true
|
||||
Layout.bottomMargin: 8
|
||||
color: MoneroComponents.Style.dividerColor
|
||||
opacity: MoneroComponents.Style.dividerOpacity
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 0
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
spacing: 0
|
||||
|
||||
MoneroComponents.TextPlain {
|
||||
id: title
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 20
|
||||
Layout.topMargin: 8
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
opacity: MoneroComponents.Style.blackTheme ? 1.0 : 0.8
|
||||
font.bold: true
|
||||
font.family: MoneroComponents.Style.fontRegular.name
|
||||
font.pixelSize: 16
|
||||
}
|
||||
|
||||
MoneroComponents.TextPlainArea {
|
||||
id: description
|
||||
color: MoneroComponents.Style.dimmedFontColor
|
||||
colorBlackTheme: MoneroComponents.Style._b_dimmedFontColor
|
||||
colorWhiteTheme: MoneroComponents.Style._w_dimmedFontColor
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: TextInput.AlignLeft
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.StandardButton {
|
||||
id: button
|
||||
small: true
|
||||
onClicked: {
|
||||
settingsListItem.clicked()
|
||||
}
|
||||
width: 135
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -82,10 +82,8 @@ Rectangle {
|
||||
|
||||
function open() {
|
||||
// Center
|
||||
if(!isMobile) {
|
||||
root.x = parent.width/2 - root.width/2
|
||||
root.y = 100
|
||||
}
|
||||
root.x = parent.width/2 - root.width/2
|
||||
root.y = 100
|
||||
root.z = 11
|
||||
root.visible = true;
|
||||
}
|
||||
@@ -96,14 +94,14 @@ Rectangle {
|
||||
}
|
||||
|
||||
// TODO: implement without hardcoding sizes
|
||||
width: isMobile ? screenWidth : 520
|
||||
height: isMobile ? screenHeight : 380
|
||||
width: 520
|
||||
height: 380
|
||||
|
||||
ColumnLayout {
|
||||
id: mainLayout
|
||||
spacing: 10
|
||||
anchors.fill: parent
|
||||
anchors.margins: (isMobile? 17 : 20)
|
||||
anchors.margins: 20
|
||||
|
||||
RowLayout {
|
||||
id: column
|
||||
|
||||
@@ -51,7 +51,6 @@ QtObject {
|
||||
property string titleBarBackgroundBorderColor: blackTheme ? _b_titleBarBackgroundBorderColor : _w_titleBarBackgroundBorderColor
|
||||
property string titleBarLogoSource: blackTheme ? _b_titleBarLogoSource : _w_titleBarLogoSource
|
||||
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 titleBarCloseSource: blackTheme ? _b_titleBarCloseSource : _w_titleBarCloseSource
|
||||
property string titleBarButtonHoverColor: blackTheme ? _b_titleBarButtonHoverColor : _w_titleBarButtonHoverColor
|
||||
@@ -108,7 +107,6 @@ QtObject {
|
||||
property string _b_titleBarBackgroundBorderColor: "#2f2f2f"
|
||||
property string _b_titleBarLogoSource: "qrc:///images/titlebarLogo.png"
|
||||
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_titleBarCloseSource: "qrc:///images/close.svg"
|
||||
property string _b_titleBarButtonHoverColor: "#10FFFFFF"
|
||||
@@ -165,7 +163,6 @@ QtObject {
|
||||
property string _w_titleBarBackgroundBorderColor: "#DEDEDE"
|
||||
property string _w_titleBarLogoSource: "qrc:///images/themes/white/titlebarLogo.png"
|
||||
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_titleBarCloseSource: "qrc:///images/themes/white/close.svg"
|
||||
property string _w_titleBarButtonHoverColor: "#11000000"
|
||||
|
||||
@@ -38,14 +38,14 @@ import "effects/" as MoneroEffects
|
||||
Rectangle {
|
||||
id: root
|
||||
property int mouseX: 0
|
||||
property bool basicButtonVisible: false
|
||||
property bool customDecorations: persistentSettings.customDecorations
|
||||
property bool showMinimizeButton: true
|
||||
property bool showMaximizeButton: true
|
||||
property bool showCloseButton: true
|
||||
property string walletName: ""
|
||||
|
||||
height: {
|
||||
if(!persistentSettings.customDecorations || isMobile) return 0;
|
||||
if(!persistentSettings.customDecorations) return 0;
|
||||
return 50;
|
||||
}
|
||||
|
||||
@@ -56,18 +56,18 @@ Rectangle {
|
||||
signal maximizeClicked
|
||||
signal minimizeClicked
|
||||
signal languageClicked
|
||||
signal goToBasicVersion(bool yes)
|
||||
signal closeWalletClicked
|
||||
|
||||
state: "default"
|
||||
states: [
|
||||
State {
|
||||
name: "default";
|
||||
PropertyChanges { target: btnSidebarCollapse; visible: true}
|
||||
PropertyChanges { target: btnCloseWallet; visible: true}
|
||||
PropertyChanges { target: btnLanguageToggle; visible: true}
|
||||
}, State {
|
||||
// show only theme switcher and window controls
|
||||
name: "essentials";
|
||||
PropertyChanges { target: btnSidebarCollapse; visible: false}
|
||||
PropertyChanges { target: btnCloseWallet; visible: false}
|
||||
PropertyChanges { target: btnLanguageToggle; visible: false}
|
||||
}
|
||||
]
|
||||
@@ -93,22 +93,20 @@ Rectangle {
|
||||
|
||||
// collapse sidebar
|
||||
Rectangle {
|
||||
id: btnSidebarCollapse
|
||||
visible: root.basicButtonVisible
|
||||
id: btnCloseWallet
|
||||
color: "transparent"
|
||||
Layout.preferredWidth: 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.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
|
||||
}
|
||||
|
||||
@@ -118,7 +116,7 @@ Rectangle {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onEntered: parent.color = MoneroComponents.Style.titleBarButtonHoverColor
|
||||
onExited: parent.color = "transparent"
|
||||
onClicked: root.goToBasicVersion(leftPanel.visible)
|
||||
onClicked: root.closeWalletClicked(leftPanel.visible)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,9 +129,10 @@ Rectangle {
|
||||
|
||||
Text {
|
||||
text: FontAwesome.globe
|
||||
font.family: FontAwesome.fontFamily
|
||||
font.family: FontAwesome.fontFamilySolid
|
||||
font.pixelSize: 16
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
font.styleName: "Solid"
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
opacity: 0.75
|
||||
@@ -156,9 +155,10 @@ Rectangle {
|
||||
Layout.preferredHeight: parent.height
|
||||
|
||||
Text {
|
||||
text: MoneroComponents.Style.blackTheme ? FontAwesome.lightbulbO : FontAwesome.moonO
|
||||
font.family: FontAwesome.fontFamily
|
||||
font.pixelSize: 16
|
||||
text: FontAwesome.moonO
|
||||
font.family: MoneroComponents.Style.blackTheme ? FontAwesome.fontFamilySolid : FontAwesome.fontFamily
|
||||
font.styleName: MoneroComponents.Style.blackTheme ? "Solid" : "Regular"
|
||||
font.pixelSize: 15
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
@@ -189,6 +189,7 @@ Rectangle {
|
||||
|
||||
// monero logo
|
||||
Item {
|
||||
visible: walletName.length === 0
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: parent.height
|
||||
|
||||
@@ -216,6 +217,22 @@ 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
|
||||
Rectangle {
|
||||
color: "transparent"
|
||||
|
||||
@@ -41,6 +41,8 @@ Item {
|
||||
property string color: ""
|
||||
property bool fontAwesomeFallbackEnabled: true
|
||||
property var fontAwesomeFallbackIcon: ""
|
||||
property string fontAwesomeFallbackFont: FontAwesome.fontFamilySolid
|
||||
property string fontAwesomeFallbackStyle: "Solid"
|
||||
property int fontAwesomeFallbackSize: 16
|
||||
property double fontAwesomeFallbackOpacity: 0.8
|
||||
property string fontAwesomeFallbackColor: MoneroComponents.Style.defaultFontColor
|
||||
@@ -74,8 +76,9 @@ Item {
|
||||
id: fontAwesomeFallback
|
||||
visible: !isOpenGL && root.fontAwesomeFallback
|
||||
text: !isOpenGL ? root.fontAwesomeFallbackIcon : ""
|
||||
font.family: FontAwesome.fontFamily
|
||||
font.family: root.fontAwesomeFallbackFont
|
||||
font.pixelSize: root.fontAwesomeFallbackSize
|
||||
font.styleName: root.fontAwesomeFallbackStyle
|
||||
color: root.fontAwesomeFallbackColor
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
@@ -4,10 +4,23 @@ import QtQuick 2.9
|
||||
Object {
|
||||
|
||||
FontLoader {
|
||||
source: "./fontawesome-webfont.ttf"
|
||||
id: regular
|
||||
source: "./fa-regular-400.ttf"
|
||||
}
|
||||
|
||||
property string fontFamily: "FontAwesome"
|
||||
FontLoader {
|
||||
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
|
||||
property string addressBook : "\uf2b9"
|
||||
@@ -594,6 +607,7 @@ Object {
|
||||
property string shower : "\uf2cc"
|
||||
property string signIn : "\uf090"
|
||||
property string signLanguage : "\uf2a7"
|
||||
property string signOutAlt : "\uf2f5"
|
||||
property string signOut : "\uf08b"
|
||||
property string signal : "\uf012"
|
||||
property string signing : "\uf2a7"
|
||||
|
||||
BIN
fonts/FontAwesome/fa-brands-400.ttf
Normal file
BIN
fonts/FontAwesome/fa-regular-400.ttf
Normal file
BIN
fonts/FontAwesome/fa-solid-900.ttf
Normal file
@@ -17,7 +17,7 @@ if [ ! -d $MONERO_DIR/src ]; then
|
||||
fi
|
||||
git submodule update --remote
|
||||
git -C $MONERO_DIR fetch
|
||||
git -C $MONERO_DIR checkout v0.14.1.0
|
||||
git -C $MONERO_DIR checkout v0.15.0.1
|
||||
|
||||
# get monero core tag
|
||||
pushd $MONERO_DIR
|
||||
@@ -253,4 +253,7 @@ if [ -d $MONERO_DIR/build/$BUILD_TYPE/external/unbound ]; then
|
||||
popd
|
||||
fi
|
||||
|
||||
# install randomx
|
||||
eval make -C $MONERO_DIR/build/$BUILD_TYPE/external/randomx all install
|
||||
|
||||
popd
|
||||
|
||||
BIN
images/card-background-black.png
Executable file
|
After Width: | Height: | Size: 24 KiB |
BIN
images/card-background-black@2x.png
Executable file
|
After Width: | Height: | Size: 68 KiB |
BIN
images/card-background-white.png
Executable file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
images/card-background-white@2x.png
Executable file
|
After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 87 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 419 B |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 436 B |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 612 B |
@@ -1,6 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 359 B |
@@ -1,7 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 371 B |
@@ -1,6 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 379 B |
BIN
images/tails-grey.png
Normal file
|
After Width: | Height: | Size: 7.7 KiB |
@@ -1,6 +0,0 @@
|
||||
<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>
|
||||
|
Before Width: | Height: | Size: 328 B |
30
installers/windows/Deterministic.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# 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.
|
||||
@@ -1,6 +1,7 @@
|
||||
; Monero Boron Butterfly GUI Wallet Installer for Windows
|
||||
; Monero Carbon Chamaeleon GUI Wallet Installer for Windows
|
||||
; Copyright (c) 2017-2019, The Monero Project
|
||||
; See LICENSE
|
||||
#define GuiVersion GetFileVersion("bin\monero-wallet-gui.exe")
|
||||
|
||||
[Setup]
|
||||
AppName=Monero GUI Wallet
|
||||
@@ -8,7 +9,8 @@ AppName=Monero GUI Wallet
|
||||
; 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
|
||||
|
||||
AppVersion=0.14.1.0
|
||||
AppVersion={#GuiVersion}
|
||||
VersionInfoVersion={#GuiVersion}
|
||||
DefaultDirName={pf}\Monero GUI Wallet
|
||||
DefaultGroupName=Monero GUI Wallet
|
||||
UninstallDisplayIcon={app}\monero-wallet-gui.exe
|
||||
@@ -21,6 +23,8 @@ DisableWelcomePage=no
|
||||
LicenseFile=LICENSE
|
||||
AppPublisher=The Monero Developer Community
|
||||
AppPublisherURL=https://getmonero.org
|
||||
TimeStampsInUTC=yes
|
||||
CompressionThreads=1
|
||||
|
||||
UsedUserAreasWarning=no
|
||||
; The above directive silences the following compiler warning:
|
||||
@@ -37,6 +41,8 @@ UsedUserAreasWarning=no
|
||||
; play a role in only in few cases as the first standard user in a Windows installation does have admin rights.
|
||||
; So, for the time being, this installer simply disregards this problem.
|
||||
|
||||
[Messages]
|
||||
SetupWindowTitle=%1 {#GuiVersion} Installer
|
||||
|
||||
[Languages]
|
||||
Name: "en"; MessagesFile: "compiler:Default.isl"
|
||||
@@ -56,19 +62,19 @@ Name: "en"; MessagesFile: "compiler:Default.isl"
|
||||
; .exe/.dll file possibly with version info).
|
||||
;
|
||||
; This is far more robust than relying on version info or on file dates (flag "comparetimestamp").
|
||||
; As of version 0.14.1.0, the Monero .exe files do not carry version info anyway in their .exe headers.
|
||||
; As of version 0.15.0.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
|
||||
; copied again, even if already present with correct file date and identical content.
|
||||
;
|
||||
; Note that it would be very dangerous to use "ignoreversion" on files that may be shared with other
|
||||
; applications somehow. Luckily this is no issue here because ALL files are "private" to Monero.
|
||||
|
||||
Source: "ReadMe.htm"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: {#file AddBackslash(SourcePath) + "ReadMe.htm"}; DestDir: "{app}"; DestName: "ReadMe.htm"; Flags: ignoreversion
|
||||
Source: "FinishImage.bmp"; Flags: dontcopy
|
||||
|
||||
; Monero GUI wallet exe and guide
|
||||
Source: "bin\monero-wallet-gui.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "bin\monero-GUI-guide.pdf"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "bin\monero-gui-wallet-guide.pdf"; DestDir: "{app}"; Flags: ignoreversion
|
||||
|
||||
; Monero CLI wallet
|
||||
Source: "bin\monero-wallet-cli.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||
@@ -195,7 +201,7 @@ begin
|
||||
// Additional wizard page for entering a special blockchain location
|
||||
blockChainDefaultDir := ExpandConstant('{commonappdata}\bitmonero');
|
||||
s := 'The default folder to store the Monero blockchain is ' + blockChainDefaultDir;
|
||||
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 + '. As this will need more than 74 GB of free space, you may want to use a folder on a different drive.';
|
||||
s := s + ' If yes, specify that folder here.';
|
||||
|
||||
BlockChainDirPage := CreateInputDirPage(wpSelectDir,
|
||||
|
||||
@@ -6,7 +6,7 @@ Copyright (c) 2017-2019, The Monero Project
|
||||
|
||||
This is a *Inno Setup* script `Monero.iss` plus some related files
|
||||
that allows you to build a standalone Windows installer (.exe) for
|
||||
the GUI wallet that comes with the Boron Butterfly release of Monero.
|
||||
the GUI wallet that comes with the Carbon Chamaeleon release of Monero.
|
||||
|
||||
This turns the GUI wallet into a more or less standard Windows program,
|
||||
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
|
||||
files and directories of the GUI wallet package to install by name,
|
||||
this version of the script only works with exactly the GUI wallet
|
||||
for Monero release *Boron Butterfly* that you find on
|
||||
for Monero release *Carbon Chamaeleon* that you find on
|
||||
[the official download page](https://getmonero.org/downloads/).
|
||||
|
||||
It should however be easy to modify the script for future
|
||||
@@ -32,13 +32,15 @@ See [LICENSE](LICENSE).
|
||||
|
||||
You can only build on Windows, and the result is always a
|
||||
Windows .exe file that can act as a standalone installer for the
|
||||
Boron Butterfly GUI wallet.
|
||||
Carbon Chamaeleon 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:
|
||||
|
||||
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 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.14.1.0`) to this `bin` subdirectory
|
||||
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`.
|
||||
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
|
||||
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
|
||||
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Monero Boron Butterfly GUI Wallet</title>
|
||||
<title>Monero Carbon Chamaeleon GUI Wallet</title>
|
||||
</head>
|
||||
|
||||
<body style="font-family: Arial, Helvetica, sans-serif">
|
||||
<h1>Monero Boron Butterfly GUI Wallet</h1>
|
||||
<h1>Monero Carbon Chamaeleon GUI Wallet</h1>
|
||||
|
||||
<p>Copyright (c) 2014-2019, The Monero Project<br>
|
||||
Date: May 7, 2019</p>
|
||||
<p>Copyright (c) 2014-2019, The Monero Project</p>
|
||||
|
||||
<h2>Preface</h2>
|
||||
|
||||
@@ -23,7 +22,7 @@
|
||||
|
||||
<h2>Content of the Package</h2>
|
||||
|
||||
<p>You just installed the <i>Monero GUI wallet</i> for Windows, release Boron Butterfly, version 0.14.1.0.
|
||||
<p>You just installed the <i>Monero GUI wallet</i> for Windows, release Carbon Chamaeleon, version {#GuiVersion}.
|
||||
The wallet enables you to send and receive Moneroj in a secure and very private way.
|
||||
</p>
|
||||
|
||||
@@ -61,7 +60,7 @@
|
||||
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
|
||||
the blockchain locally (somewhat over 70 GB in May 2019, and of course growing), you can compromise and try to connect
|
||||
the blockchain locally (somewhat over 74 GB in November 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
|
||||
<a href="https://moneroworld.com/#nodes">this page</a>.
|
||||
</p>
|
||||
|
||||
|
Before Width: | Height: | Size: 440 KiB After Width: | Height: | Size: 440 KiB |
@@ -1 +0,0 @@
|
||||
-----
|
||||
@@ -12,13 +12,13 @@ function destinationsToAddress(destinations){
|
||||
}
|
||||
|
||||
function addressTruncate(address, range){
|
||||
if(typeof(address) === "undefined") return;
|
||||
if(typeof(address) === "undefined") return "";
|
||||
if(typeof(range) === "undefined") range = 8;
|
||||
return address.substring(0, range) + "..." + address.substring(address.length-range);
|
||||
}
|
||||
|
||||
function addressTruncatePretty(address, blocks){
|
||||
if(typeof(address) === "undefined") return;
|
||||
if(typeof(address) === "undefined") return "";
|
||||
if(typeof(blocks) === "undefined") blocks = 2;
|
||||
blocks = blocks <= 1 ? 1 : blocks >= 23 ? 23 : blocks;
|
||||
var ret = "";
|
||||
|
||||
42
js/Utils.js
@@ -46,7 +46,6 @@ function showSeedPage() {
|
||||
leftPanel.selectItem(middlePanel.state);
|
||||
}
|
||||
passwordDialog.open();
|
||||
if(isMobile) hideMenu();
|
||||
updateBalance();
|
||||
}
|
||||
|
||||
@@ -94,16 +93,6 @@ function netTypeToString(){
|
||||
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(){
|
||||
return Math.floor((new Date).getTime()/1000);
|
||||
}
|
||||
@@ -112,25 +101,6 @@ function roundDownToNearestThousand(_num){
|
||||
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){
|
||||
// Traverse QML object tree and return components that match
|
||||
// via property names. Similar to jQuery("myclass").each(...
|
||||
@@ -163,15 +133,3 @@ function capitalize(s){
|
||||
if (typeof s !== 'string') return ''
|
||||
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) : "");
|
||||
};
|
||||
|
||||
@@ -39,10 +39,8 @@ function switchPage(next) {
|
||||
console.log("switchpage: currentPage: ", currentPage);
|
||||
|
||||
// Update prev/next button positions for mobile/desktop
|
||||
prevButton.anchors.verticalCenter = (!isMobile) ? wizard.verticalCenter : undefined
|
||||
prevButton.anchors.bottom = (isMobile) ? wizard.bottom : undefined
|
||||
nextButton.anchors.verticalCenter = (!isMobile) ? wizard.verticalCenter : undefined
|
||||
nextButton.anchors.bottom = (isMobile) ? wizard.bottom : undefined
|
||||
prevButton.anchors.verticalCenter = wizard.verticalCenter
|
||||
nextButton.anchors.verticalCenter = wizard.verticalCenter
|
||||
|
||||
if (currentPage > 0 || currentPage < pages.length - 1) {
|
||||
pages[currentPage].opacity = 0
|
||||
|
||||
@@ -51,4 +51,12 @@ SCRIPT_DIR="\$(dirname "\$(test -L "\${BASH_SOURCE[0]}" && readlink "\${BASH_SOU
|
||||
"\$SCRIPT_DIR"/$GUI_EXEC "\$@"
|
||||
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-tails.AppImage
|
||||
|
||||
56
main.cpp
@@ -64,8 +64,9 @@
|
||||
#include "MainApp.h"
|
||||
#include "qt/ipc.h"
|
||||
#include "qt/utils.h"
|
||||
#include "qt/mime.h"
|
||||
#include "src/qt/TailsOS.h"
|
||||
#include "src/qt/KeysFiles.h"
|
||||
#include "src/qt/MoneroSettings.h"
|
||||
#include "qt/prices.h"
|
||||
|
||||
// IOS exclusions
|
||||
@@ -82,6 +83,7 @@ bool isAndroid = false;
|
||||
bool isWindows = false;
|
||||
bool isMac = false;
|
||||
bool isLinux = false;
|
||||
bool isTails = false;
|
||||
bool isDesktop = false;
|
||||
bool isOpenGL = true;
|
||||
|
||||
@@ -101,6 +103,7 @@ int main(int argc, char *argv[])
|
||||
bool isWindows = true;
|
||||
#elif defined(Q_OS_LINUX)
|
||||
bool isLinux = true;
|
||||
bool isTails = TailsOS::detect();
|
||||
#elif defined(Q_OS_MAC)
|
||||
bool isMac = true;
|
||||
#endif
|
||||
@@ -122,18 +125,8 @@ int main(int argc, char *argv[])
|
||||
// qDebug() << "High DPI auto scaling - enabled";
|
||||
//#endif
|
||||
|
||||
QString moneroAccountsDir;
|
||||
#if defined(Q_OS_WIN) || defined(Q_OS_IOS)
|
||||
QStringList moneroAccountsRootDir = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation);
|
||||
#else
|
||||
QStringList moneroAccountsRootDir = QStandardPaths::standardLocations(QStandardPaths::HomeLocation);
|
||||
#endif
|
||||
if (!moneroAccountsRootDir.empty()) {
|
||||
moneroAccountsDir = moneroAccountsRootDir.at(0) + "/Monero/wallets";
|
||||
} else {
|
||||
qCritical() << "Error: accounts root directory could not be set";
|
||||
return 1;
|
||||
}
|
||||
// Turn off colors in monerod log output.
|
||||
qputenv("TERM", "goaway");
|
||||
|
||||
MainApp app(argc, argv);
|
||||
|
||||
@@ -141,6 +134,34 @@ int main(int argc, char *argv[])
|
||||
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;
|
||||
#if defined(Q_OS_WIN) || defined(Q_OS_IOS)
|
||||
QStringList moneroAccountsRootDir = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation);
|
||||
#else
|
||||
QStringList moneroAccountsRootDir = QStandardPaths::standardLocations(QStandardPaths::HomeLocation);
|
||||
#endif
|
||||
|
||||
if(isTails && TailsOS::usePersistence){
|
||||
moneroAccountsDir = QDir::homePath() + "/Persistent/Monero/wallets";
|
||||
} else if (!moneroAccountsRootDir.empty()) {
|
||||
moneroAccountsDir = moneroAccountsRootDir.at(0) + "/Monero/wallets";
|
||||
} else {
|
||||
qCritical() << "Error: accounts root directory could not be set";
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if defined(Q_OS_LINUX)
|
||||
if (isDesktop) app.setWindowIcon(QIcon(":/images/appicon.ico"));
|
||||
#endif
|
||||
@@ -173,6 +194,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
qWarning().noquote() << "app startd" << "(log: " + logPath + ")";
|
||||
|
||||
// Desktop entry
|
||||
#ifdef Q_OS_LINUX
|
||||
registerXdgMime(app);
|
||||
#endif
|
||||
@@ -224,6 +246,9 @@ int main(int argc, char *argv[])
|
||||
// registering types for QML
|
||||
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");
|
||||
|
||||
|
||||
@@ -313,6 +338,8 @@ int main(int argc, char *argv[])
|
||||
|
||||
engine.rootContext()->setContextProperty("walletLogPath", logPath);
|
||||
|
||||
engine.rootContext()->setContextProperty("tailsUsePersistence", TailsOS::usePersistence);
|
||||
|
||||
// Exclude daemon manager from IOS
|
||||
#ifndef Q_OS_IOS
|
||||
const QStringList arguments = (QStringList) QCoreApplication::arguments().at(0);
|
||||
@@ -326,7 +353,7 @@ int main(int argc, char *argv[])
|
||||
engine.rootContext()->setContextProperty("isIOS", isIOS);
|
||||
engine.rootContext()->setContextProperty("isAndroid", isAndroid);
|
||||
engine.rootContext()->setContextProperty("isOpenGL", isOpenGL);
|
||||
engine.rootContext()->setContextProperty("isLinux", isLinux);
|
||||
engine.rootContext()->setContextProperty("isTails", isTails);
|
||||
|
||||
engine.rootContext()->setContextProperty("screenWidth", geo.width());
|
||||
engine.rootContext()->setContextProperty("screenHeight", geo.height());
|
||||
@@ -350,6 +377,7 @@ int main(int argc, char *argv[])
|
||||
accountName = "My monero Account";
|
||||
|
||||
engine.rootContext()->setContextProperty("defaultAccountName", accountName);
|
||||
engine.rootContext()->setContextProperty("homePath", QDir::homePath());
|
||||
engine.rootContext()->setContextProperty("applicationDirectory", QApplication::applicationDirPath());
|
||||
engine.rootContext()->setContextProperty("idealThreadCount", QThread::idealThreadCount());
|
||||
|
||||
|
||||
552
main.qml
@@ -31,11 +31,11 @@ import QtQuick.Window 2.0
|
||||
import QtQuick.Controls 1.1
|
||||
import QtQuick.Controls.Styles 1.1
|
||||
import QtQuick.Dialogs 1.2
|
||||
import Qt.labs.settings 1.0
|
||||
|
||||
import moneroComponents.Wallet 1.0
|
||||
import moneroComponents.PendingTransaction 1.0
|
||||
import moneroComponents.NetworkType 1.0
|
||||
import moneroComponents.Settings 1.0
|
||||
|
||||
import "components"
|
||||
import "components" as MoneroComponents
|
||||
@@ -69,7 +69,6 @@ ApplicationWindow {
|
||||
property bool foundNewBlock: false
|
||||
property bool qrScannerEnabled: (typeof builtWithScanner != "undefined") && builtWithScanner
|
||||
property int blocksToSync: 1
|
||||
property var isMobile: (appWindow.width > 700 && !isAndroid) ? false : true
|
||||
property bool isMining: false
|
||||
property int walletMode: persistentSettings.walletMode
|
||||
property var cameraUi
|
||||
@@ -87,8 +86,8 @@ ApplicationWindow {
|
||||
property bool themeTransition: false
|
||||
|
||||
// fiat price conversion
|
||||
property int fiatPriceXMRUSD: 0
|
||||
property int fiatPriceXMREUR: 0
|
||||
property real fiatPriceXMRUSD: 0
|
||||
property real fiatPriceXMREUR: 0
|
||||
property var fiatPriceAPIs: {
|
||||
return {
|
||||
"kraken": {
|
||||
@@ -106,19 +105,6 @@ 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
|
||||
property bool walletInitialized : false
|
||||
|
||||
@@ -239,7 +225,6 @@ ApplicationWindow {
|
||||
if (typeof currentWallet !== "undefined" && currentWallet !== null) {
|
||||
console.log("Daemon change - closing " + currentWallet)
|
||||
closeWallet();
|
||||
currentWallet = undefined
|
||||
} else if (!walletInitialized) {
|
||||
// set page to transfer if not changing daemon
|
||||
middlePanel.state = "Transfer";
|
||||
@@ -283,31 +268,46 @@ ApplicationWindow {
|
||||
titleBar.visible = persistentSettings.customDecorations;
|
||||
}
|
||||
|
||||
function closeWallet() {
|
||||
function closeWallet(callback) {
|
||||
|
||||
// Disconnect all listeners
|
||||
if (typeof currentWallet !== "undefined" && currentWallet !== null) {
|
||||
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);
|
||||
if (typeof currentWallet === "undefined" || currentWallet === null) {
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
currentWallet = undefined;
|
||||
walletManager.closeWallet();
|
||||
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;
|
||||
|
||||
appWindow.showProcessingSplash(qsTr("Closing wallet..."));
|
||||
if (callback) {
|
||||
walletManager.closeWalletAsync(function() {
|
||||
hideProcessingSplash();
|
||||
callback();
|
||||
});
|
||||
} else {
|
||||
walletManager.closeWallet();
|
||||
hideProcessingSplash();
|
||||
}
|
||||
}
|
||||
|
||||
function connectWallet(wallet) {
|
||||
@@ -335,7 +335,6 @@ ApplicationWindow {
|
||||
}
|
||||
|
||||
walletName = usefulName(wallet.path)
|
||||
updateSyncing(false)
|
||||
|
||||
viewOnly = currentWallet.viewOnly;
|
||||
|
||||
@@ -376,11 +375,21 @@ ApplicationWindow {
|
||||
currentDaemonAddress = localDaemonAddress
|
||||
|
||||
console.log("initializing with daemon address: ", currentDaemonAddress)
|
||||
currentWallet.initAsync(currentDaemonAddress, 0, persistentSettings.is_recovering, persistentSettings.is_recovering_from_device, persistentSettings.restore_height);
|
||||
currentWallet.initAsync(
|
||||
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
|
||||
currentWallet.setPassword(walletPassword);
|
||||
}
|
||||
|
||||
function isTrustedDaemon() {
|
||||
return !persistentSettings.useRemoteNode || persistentSettings.is_trusted_daemon;
|
||||
}
|
||||
|
||||
function walletPath() {
|
||||
var wallet_path = persistentSettings.wallet_path
|
||||
return wallet_path;
|
||||
@@ -397,24 +406,22 @@ ApplicationWindow {
|
||||
if (!currentWallet)
|
||||
return;
|
||||
|
||||
var balance_unlocked = qsTr("HIDDEN");
|
||||
var balance = qsTr("HIDDEN");
|
||||
var balance = "?.??";
|
||||
var balanceU = "?.??";
|
||||
if(!hideBalanceForced && !persistentSettings.hideBalance){
|
||||
balance_unlocked = walletManager.displayAmount(currentWallet.unlockedBalance(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) {
|
||||
appWindow.fiatApiUpdateBalance(balance, balance_unlocked);
|
||||
appWindow.fiatApiUpdateBalance(balance);
|
||||
}
|
||||
|
||||
var accountLabel = currentWallet.getSubaddressLabel(currentWallet.currentSubaddressAccount, 0);
|
||||
leftPanel.balanceLabelText = qsTr("Balance (#%1%2)").arg(currentWallet.currentSubaddressAccount).arg(accountLabel === "" ? "" : (" – " + accountLabel));
|
||||
leftPanel.minutesToUnlock = (balance !== balanceU) ? currentWallet.history.minutesToUnlock : "";
|
||||
leftPanel.currentAccountIndex = currentWallet.currentSubaddressAccount;
|
||||
leftPanel.currentAccountLabel = currentWallet.getSubaddressLabel(currentWallet.currentSubaddressAccount, 0);
|
||||
leftPanel.balanceString = balance
|
||||
leftPanel.balanceUnlockedString = balanceU
|
||||
}
|
||||
|
||||
function onUriHandler(uri){
|
||||
@@ -453,10 +460,6 @@ ApplicationWindow {
|
||||
// Raise window
|
||||
appWindow.raise();
|
||||
appWindow.show();
|
||||
|
||||
// @TODO: remove after paymentID deprecation
|
||||
if(params.hasOwnProperty("tx_payment_id"))
|
||||
persistentSettings.showPid = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -466,15 +469,19 @@ ApplicationWindow {
|
||||
leftPanel.networkStatus.connected = status
|
||||
|
||||
// update local daemon status.
|
||||
if(!isMobile && walletManager.isDaemonLocal(currentDaemonAddress))
|
||||
if(walletManager.isDaemonLocal(currentDaemonAddress))
|
||||
daemonRunning = status;
|
||||
|
||||
// Update fee multiplier dropdown on transfer page
|
||||
middlePanel.transferView.updatePriorityDropdown();
|
||||
|
||||
// If wallet isnt connected, advanced wallet mode and no daemon is running - Ask
|
||||
if(!isMobile && appWindow.walletMode >= 2 && walletManager.isDaemonLocal(currentDaemonAddress) && !walletInitialized && status === Wallet.ConnectionStatus_Disconnected && !daemonManager.running(persistentSettings.nettype)){
|
||||
daemonManagerDialog.open();
|
||||
if (appWindow.walletMode >= 2 && walletManager.isDaemonLocal(currentDaemonAddress) && !walletInitialized && status === Wallet.ConnectionStatus_Disconnected) {
|
||||
daemonManager.runningAsync(persistentSettings.nettype, function(running) {
|
||||
if (!running) {
|
||||
daemonManagerDialog.open();
|
||||
}
|
||||
});
|
||||
}
|
||||
// initialize transaction history once wallet is initialized first time;
|
||||
if (!walletInitialized) {
|
||||
@@ -558,26 +565,21 @@ ApplicationWindow {
|
||||
}
|
||||
}
|
||||
|
||||
function onWalletClosed(walletAddress) {
|
||||
hideProcessingSplash();
|
||||
console.log(">>> wallet closed: " + walletAddress)
|
||||
}
|
||||
|
||||
function onWalletPassphraseNeeded(){
|
||||
if(rootItem.state !== "normal") return;
|
||||
|
||||
hideProcessingSplash();
|
||||
|
||||
console.log(">>> wallet passphrase needed: ")
|
||||
passphraseDialog.onAcceptedCallback = function() {
|
||||
walletManager.onPassphraseEntered(passphraseDialog.passphrase);
|
||||
passwordDialog.onAcceptedPassphraseCallback = function() {
|
||||
walletManager.onPassphraseEntered(passwordDialog.password);
|
||||
this.onWalletOpening();
|
||||
}
|
||||
passphraseDialog.onRejectedCallback = function() {
|
||||
passwordDialog.onRejectedPassphraseCallback = function() {
|
||||
walletManager.onPassphraseEntered("", true);
|
||||
this.onWalletOpening();
|
||||
}
|
||||
passphraseDialog.open()
|
||||
passwordDialog.openPassphraseDialog()
|
||||
}
|
||||
|
||||
function onWalletUpdate() {
|
||||
@@ -588,8 +590,6 @@ ApplicationWindow {
|
||||
foundNewBlock = false;
|
||||
console.log("New block found - updating history")
|
||||
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")
|
||||
middlePanel.historyView.update();
|
||||
@@ -600,7 +600,7 @@ ApplicationWindow {
|
||||
console.log("connecting remote node");
|
||||
persistentSettings.useRemoteNode = true;
|
||||
currentDaemonAddress = persistentSettings.remoteNodeAddress;
|
||||
currentWallet.initAsync(currentDaemonAddress);
|
||||
currentWallet.initAsync(currentDaemonAddress, isTrustedDaemon());
|
||||
walletManager.setDaemonAddressAsync(currentDaemonAddress);
|
||||
}
|
||||
|
||||
@@ -611,7 +611,7 @@ ApplicationWindow {
|
||||
console.log("disconnecting remote node");
|
||||
persistentSettings.useRemoteNode = false;
|
||||
currentDaemonAddress = localDaemonAddress
|
||||
currentWallet.initAsync(currentDaemonAddress);
|
||||
currentWallet.initAsync(currentDaemonAddress, isTrustedDaemon());
|
||||
walletManager.setDaemonAddressAsync(currentDaemonAddress);
|
||||
}
|
||||
|
||||
@@ -633,7 +633,7 @@ ApplicationWindow {
|
||||
}
|
||||
|
||||
// Update wallet sync progress
|
||||
updateSyncing((currentWallet.connected() !== Wallet.ConnectionStatus_Disconnected) && !daemonSynced)
|
||||
leftPanel.isSyncing = (currentWallet.connected() !== Wallet.ConnectionStatus_Disconnected) && !daemonSynced
|
||||
// Update transfer page status
|
||||
middlePanel.updateStatus();
|
||||
|
||||
@@ -683,8 +683,8 @@ ApplicationWindow {
|
||||
simpleModeConnectionTimer.stop();
|
||||
|
||||
appWindow.showProcessingSplash(qsTr("Waiting for daemon to start..."))
|
||||
daemonManager.start(flags, persistentSettings.nettype, persistentSettings.blockchainDataDir, persistentSettings.bootstrapNodeAddress);
|
||||
persistentSettings.daemonFlags = flags
|
||||
const noSync = appWindow.walletMode === 0;
|
||||
daemonManager.start(flags, persistentSettings.nettype, persistentSettings.blockchainDataDir, persistentSettings.bootstrapNodeAddress, noSync);
|
||||
}
|
||||
|
||||
function stopDaemon(){
|
||||
@@ -700,6 +700,7 @@ ApplicationWindow {
|
||||
// resume refresh
|
||||
currentWallet.startRefresh();
|
||||
// resume simplemode connection timer
|
||||
appWindow.disconnectedEpoch = Utils.epoch();
|
||||
simpleModeConnectionTimer.start();
|
||||
}
|
||||
function onDaemonStopped(){
|
||||
@@ -837,7 +838,9 @@ ApplicationWindow {
|
||||
", priority: ", priority,
|
||||
", description: ", description);
|
||||
|
||||
showProcessingSplash("Creating transaction");
|
||||
var splashMsg = qsTr("Creating transaction...");
|
||||
splashMsg += appWindow.currentWallet.isLedger() ? qsTr("\n\nPlease check your hardware wallet –\nyour input may be required.") : "";
|
||||
showProcessingSplash(splashMsg);
|
||||
|
||||
transactionDescription = description;
|
||||
|
||||
@@ -1075,12 +1078,6 @@ ApplicationWindow {
|
||||
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
|
||||
function enableUI(enable) {
|
||||
middlePanel.enabled = enable;
|
||||
@@ -1105,37 +1102,27 @@ ApplicationWindow {
|
||||
console.log("Hiding processing splash")
|
||||
splash.close();
|
||||
|
||||
leftPanel.enabled = true
|
||||
middlePanel.enabled = true
|
||||
titleBar.enabled = true
|
||||
inactiveOverlay.visible = false;
|
||||
if (!passwordDialog.visible) {
|
||||
leftPanel.enabled = true
|
||||
middlePanel.enabled = true
|
||||
titleBar.enabled = true
|
||||
inactiveOverlay.visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
// close wallet and show wizard
|
||||
function showWizard(){
|
||||
clearMoneroCardLabelText();
|
||||
walletInitialized = false;
|
||||
closeWallet();
|
||||
currentWallet = undefined;
|
||||
wizard.restart();
|
||||
wizard.wizardState = "wizardHome";
|
||||
rootItem.state = "wizard"
|
||||
// reset balance
|
||||
leftPanel.balanceText = leftPanel.unlockedBalanceText = walletManager.displayAmount(0);
|
||||
fiatApiUpdateBalance(0, 0);
|
||||
// disable timers
|
||||
userInActivityTimer.running = false;
|
||||
simpleModeConnectionTimer.running = false;
|
||||
}
|
||||
|
||||
function hideMenu() {
|
||||
goToBasicAnimation.start();
|
||||
console.log(appWindow.width)
|
||||
}
|
||||
|
||||
function showMenu() {
|
||||
goToProAnimation.start();
|
||||
console.log(appWindow.width)
|
||||
closeWallet(function() {
|
||||
wizard.restart();
|
||||
wizard.wizardState = "wizardHome";
|
||||
rootItem.state = "wizard"
|
||||
// reset balance
|
||||
clearMoneroCardLabelText();
|
||||
// disable timers
|
||||
userInActivityTimer.running = false;
|
||||
simpleModeConnectionTimer.running = false;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1254,22 +1241,34 @@ ApplicationWindow {
|
||||
Prices.getJSON(url);
|
||||
}
|
||||
|
||||
function fiatApiUpdateBalance(balance, unlocked_balance){
|
||||
// update balance card
|
||||
var ticker = persistentSettings.fiatPriceCurrency === "xmrusd" ? appWindow.fiatPriceXMRUSD : appWindow.fiatPriceXMREUR;
|
||||
var symbol = persistentSettings.fiatPriceCurrency === "xmrusd" ? "$" : "€"
|
||||
if(ticker <= 0){
|
||||
console.log(fiatApiError("Could not update balance card; invalid ticker value"));
|
||||
leftPanel.unlockedBalanceTextFiat = "N/A";
|
||||
leftPanel.balanceTextFiat = "N/A";
|
||||
return;
|
||||
function fiatApiCurrencySymbol() {
|
||||
switch (persistentSettings.fiatPriceCurrency) {
|
||||
case "xmrusd":
|
||||
return "USD";
|
||||
case "xmreur":
|
||||
return "EUR";
|
||||
default:
|
||||
console.error("unsupported currency", persistentSettings.fiatPriceCurrency);
|
||||
return "UNSUPPORTED";
|
||||
}
|
||||
}
|
||||
|
||||
var uFiat = Utils.formatMoney(unlocked_balance * ticker);
|
||||
var bFiat = Utils.formatMoney(balance * ticker);
|
||||
function fiatApiConvertToFiat(amount) {
|
||||
var ticker = persistentSettings.fiatPriceCurrency === "xmrusd" ? appWindow.fiatPriceXMRUSD : appWindow.fiatPriceXMREUR;
|
||||
if(ticker <= 0){
|
||||
console.log(fiatApiError("Invalid ticker value: " + ticker));
|
||||
return "?.??";
|
||||
}
|
||||
return (amount * ticker).toFixed(2);
|
||||
}
|
||||
|
||||
leftPanel.unlockedBalanceTextFiat = symbol + uFiat;
|
||||
leftPanel.balanceTextFiat = symbol + bFiat;
|
||||
function fiatApiUpdateBalance(balance){
|
||||
// update balance card
|
||||
var bFiat = "?.??"
|
||||
if (!hideBalanceForced && !persistentSettings.hideBalance) {
|
||||
bFiat = fiatApiConvertToFiat(balance);
|
||||
}
|
||||
leftPanel.balanceFiatString = bFiat;
|
||||
}
|
||||
|
||||
function fiatTimerStart(){
|
||||
@@ -1287,9 +1286,11 @@ ApplicationWindow {
|
||||
Component.onCompleted: {
|
||||
x = (Screen.width - width) / 2
|
||||
y = (Screen.height - maxWindowHeight) / 2
|
||||
|
||||
applyWalletMode(persistentSettings.walletMode);
|
||||
|
||||
//
|
||||
walletManager.walletOpened.connect(onWalletOpened);
|
||||
walletManager.walletClosed.connect(onWalletClosed);
|
||||
walletManager.deviceButtonRequest.connect(onDeviceButtonRequest);
|
||||
walletManager.deviceButtonPressed.connect(onDeviceButtonPressed);
|
||||
walletManager.checkUpdatesComplete.connect(onWalletCheckUpdatesComplete);
|
||||
@@ -1341,8 +1342,14 @@ ApplicationWindow {
|
||||
}
|
||||
}
|
||||
|
||||
Settings {
|
||||
MoneroSettings {
|
||||
id: persistentSettings
|
||||
fileName: {
|
||||
if(isTails && tailsUsePersistence)
|
||||
return homePath + "/Persistent/Monero/monero-core.conf";
|
||||
return "";
|
||||
}
|
||||
|
||||
property string language
|
||||
property string locale
|
||||
property string account_name
|
||||
@@ -1371,7 +1378,6 @@ ApplicationWindow {
|
||||
property bool useRemoteNode: false
|
||||
property string remoteNodeAddress: ""
|
||||
property string bootstrapNodeAddress: ""
|
||||
property string remoteNodeRegion: ""
|
||||
property bool segregatePreForkOutputs: true
|
||||
property bool keyReuseMitigation2: true
|
||||
property int segregationHeight: 0
|
||||
@@ -1379,9 +1385,7 @@ ApplicationWindow {
|
||||
property bool hideBalance: false
|
||||
property bool lockOnUserInActivity: true
|
||||
property int walletMode: 2
|
||||
property string remoteNodeService: ""
|
||||
property int lockOnUserInActivityInterval: 10 // minutes
|
||||
property bool showPid: false
|
||||
property bool blackTheme: true
|
||||
|
||||
property bool fiatPriceEnabled: false
|
||||
@@ -1494,23 +1498,6 @@ ApplicationWindow {
|
||||
}
|
||||
}
|
||||
|
||||
PassphraseDialog {
|
||||
id: passphraseDialog
|
||||
visible: false
|
||||
z: parent.z + 1
|
||||
anchors.fill: parent
|
||||
property var onAcceptedCallback
|
||||
property var onRejectedCallback
|
||||
onAccepted: {
|
||||
if (onAcceptedCallback)
|
||||
onAcceptedCallback();
|
||||
}
|
||||
onRejected: {
|
||||
if (onRejectedCallback)
|
||||
onRejectedCallback();
|
||||
}
|
||||
}
|
||||
|
||||
PasswordDialog {
|
||||
id: passwordDialog
|
||||
visible: false
|
||||
@@ -1518,6 +1505,8 @@ ApplicationWindow {
|
||||
anchors.fill: parent
|
||||
property var onAcceptedCallback
|
||||
property var onRejectedCallback
|
||||
property var onAcceptedPassphraseCallback
|
||||
property var onRejectedPassphraseCallback
|
||||
onAccepted: {
|
||||
if (onAcceptedCallback)
|
||||
onAcceptedCallback();
|
||||
@@ -1526,16 +1515,9 @@ ApplicationWindow {
|
||||
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;
|
||||
onAcceptedNewPassword: {
|
||||
if (currentWallet.setPassword(passwordDialog.password)) {
|
||||
appWindow.walletPassword = passwordDialog.password;
|
||||
informationPopup.title = qsTr("Information") + translationManager.emptyString;
|
||||
informationPopup.text = qsTr("Password changed successfully") + translationManager.emptyString;
|
||||
informationPopup.icon = StandardIcon.Information;
|
||||
@@ -1547,7 +1529,14 @@ ApplicationWindow {
|
||||
informationPopup.onCloseCallback = null;
|
||||
informationPopup.open();
|
||||
}
|
||||
onRejected: {
|
||||
onRejectedNewPassword: {}
|
||||
onAcceptedPassphrase: {
|
||||
if (onAcceptedPassphraseCallback)
|
||||
onAcceptedPassphraseCallback();
|
||||
}
|
||||
onRejectedPassphrase: {
|
||||
if (onRejectedPassphraseCallback)
|
||||
onRejectedPassphraseCallback();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1595,153 +1584,89 @@ ApplicationWindow {
|
||||
states: [
|
||||
State {
|
||||
name: "wizard"
|
||||
PropertyChanges { target: leftPanel; visible: false }
|
||||
PropertyChanges { target: middlePanel; visible: false }
|
||||
PropertyChanges { target: wizard; visible: true }
|
||||
PropertyChanges { target: resizeArea; visible: true }
|
||||
PropertyChanges { target: mobileHeader; visible: false }
|
||||
PropertyChanges { target: titleBar; state: "essentials" }
|
||||
}, State {
|
||||
name: "normal"
|
||||
PropertyChanges { target: leftPanel; visible: (isMobile)? false : true }
|
||||
PropertyChanges { target: middlePanel; visible: true }
|
||||
PropertyChanges { target: titleBar; basicButtonVisible: true }
|
||||
PropertyChanges { target: wizard; visible: false }
|
||||
PropertyChanges { target: resizeArea; visible: true }
|
||||
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 {
|
||||
id: leftPanel
|
||||
anchors.top: mobileHeader.bottom
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.bottom: parent.bottom
|
||||
visible: rootItem.state == "normal" && middlePanel.state != "Merchant"
|
||||
|
||||
onTransferClicked: {
|
||||
middlePanel.state = "Transfer";
|
||||
middlePanel.flickable.contentY = 0;
|
||||
if(isMobile) {
|
||||
hideMenu();
|
||||
}
|
||||
updateBalance();
|
||||
}
|
||||
|
||||
onReceiveClicked: {
|
||||
middlePanel.state = "Receive";
|
||||
middlePanel.flickable.contentY = 0;
|
||||
if(isMobile) {
|
||||
hideMenu();
|
||||
}
|
||||
updateBalance();
|
||||
}
|
||||
|
||||
onMerchantClicked: {
|
||||
middlePanel.state = "Merchant";
|
||||
middlePanel.flickable.contentY = 0;
|
||||
if(isMobile) {
|
||||
hideMenu();
|
||||
}
|
||||
updateBalance();
|
||||
}
|
||||
|
||||
onTxkeyClicked: {
|
||||
middlePanel.state = "TxKey";
|
||||
middlePanel.flickable.contentY = 0;
|
||||
if(isMobile) {
|
||||
hideMenu();
|
||||
}
|
||||
updateBalance();
|
||||
}
|
||||
|
||||
onSharedringdbClicked: {
|
||||
middlePanel.state = "SharedRingDB";
|
||||
middlePanel.flickable.contentY = 0;
|
||||
if(isMobile) {
|
||||
hideMenu();
|
||||
}
|
||||
updateBalance();
|
||||
}
|
||||
|
||||
onHistoryClicked: {
|
||||
middlePanel.state = "History";
|
||||
middlePanel.flickable.contentY = 0;
|
||||
if(isMobile) {
|
||||
hideMenu();
|
||||
}
|
||||
updateBalance();
|
||||
}
|
||||
|
||||
onAddressBookClicked: {
|
||||
middlePanel.state = "AddressBook";
|
||||
middlePanel.flickable.contentY = 0;
|
||||
if(isMobile) {
|
||||
hideMenu();
|
||||
}
|
||||
updateBalance();
|
||||
}
|
||||
|
||||
onMiningClicked: {
|
||||
middlePanel.state = "Mining";
|
||||
middlePanel.flickable.contentY = 0;
|
||||
if(isMobile) {
|
||||
hideMenu();
|
||||
}
|
||||
updateBalance();
|
||||
}
|
||||
|
||||
onSignClicked: {
|
||||
middlePanel.state = "Sign";
|
||||
middlePanel.flickable.contentY = 0;
|
||||
if(isMobile) {
|
||||
hideMenu();
|
||||
}
|
||||
updateBalance();
|
||||
}
|
||||
|
||||
onSettingsClicked: {
|
||||
middlePanel.state = "Settings";
|
||||
middlePanel.flickable.contentY = 0;
|
||||
if(isMobile) {
|
||||
hideMenu();
|
||||
}
|
||||
updateBalance();
|
||||
}
|
||||
|
||||
onAccountClicked: {
|
||||
middlePanel.state = "Account";
|
||||
middlePanel.flickable.contentY = 0;
|
||||
if(isMobile) {
|
||||
hideMenu();
|
||||
}
|
||||
updateBalance();
|
||||
}
|
||||
}
|
||||
@@ -1749,102 +1674,13 @@ ApplicationWindow {
|
||||
|
||||
MiddlePanel {
|
||||
id: middlePanel
|
||||
anchors.top: mobileHeader.bottom
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: leftPanel.visible ? leftPanel.right : parent.left
|
||||
anchors.right: parent.right
|
||||
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 {
|
||||
id: wizard
|
||||
anchors.fill: parent
|
||||
@@ -1909,21 +1745,14 @@ ApplicationWindow {
|
||||
TitleBar {
|
||||
id: titleBar
|
||||
visible: persistentSettings.customDecorations && middlePanel.state !== "Merchant"
|
||||
walletName: appWindow.walletName
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
onCloseClicked: appWindow.close();
|
||||
onLanguageClicked: appWindow.toggleLanguageView();
|
||||
onCloseWalletClicked: appWindow.showWizard();
|
||||
onMaximizeClicked: appWindow.visibility = appWindow.visibility !== Window.Maximized ? Window.Maximized : Window.Windowed
|
||||
onMinimizeClicked: appWindow.visibility = Window.Minimized
|
||||
onGoToBasicVersion: {
|
||||
if (yes) {
|
||||
// basicPanel.currentView = middlePanel.currentView
|
||||
goToBasicAnimation.start()
|
||||
} else {
|
||||
// middlePanel.currentView = basicPanel.currentView
|
||||
goToProAnimation.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MoneroMerchant.MerchantTitlebar {
|
||||
@@ -2007,41 +1836,43 @@ ApplicationWindow {
|
||||
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(){
|
||||
// auto-connection mechanism for simple mode
|
||||
if(persistentSettings.nettype != NetworkType.MAINNET) return;
|
||||
if(appWindow.walletMode >= 2) return;
|
||||
|
||||
var disconnected = leftPanel.networkStatus.connected === Wallet.ConnectionStatus_Disconnected;
|
||||
var disconnectedEpoch = appWindow.disconnectedEpoch;
|
||||
if(disconnectedEpoch === 0){
|
||||
const disconnectedTimeoutSec = 30;
|
||||
const firstCheckDelaySec = 2;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
// disconnected longer than 5 seconds?
|
||||
if(disconnected && disconnectedEpoch > 0 && (Utils.epoch() - disconnectedEpoch) >= 5){
|
||||
// for bootstrap mode, first wait until daemon is killed
|
||||
if(appWindow.walletMode === 1 && appWindow.daemonRunning) {
|
||||
appWindow.stopDaemon();
|
||||
return;
|
||||
}
|
||||
|
||||
// fetch new node list
|
||||
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);
|
||||
});
|
||||
const sinceLastConnect = Utils.epoch() - appWindow.disconnectedEpoch;
|
||||
if (sinceLastConnect < disconnectedTimeoutSec && checkNoSyncFlag()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (appWindow.daemonRunning) {
|
||||
appWindow.stopDaemon();
|
||||
}
|
||||
appWindow.startDaemon("");
|
||||
}
|
||||
|
||||
Timer {
|
||||
@@ -2120,7 +1951,12 @@ ApplicationWindow {
|
||||
closeAccepted();
|
||||
};
|
||||
|
||||
confirmationDialog.open()
|
||||
if (appWindow.walletMode == 0) {
|
||||
stopDaemon();
|
||||
closeAccepted();
|
||||
} else {
|
||||
confirmationDialog.open();
|
||||
}
|
||||
|
||||
} else {
|
||||
closeAccepted();
|
||||
@@ -2131,8 +1967,8 @@ ApplicationWindow {
|
||||
console.log("close accepted");
|
||||
// Close wallet non async on exit
|
||||
daemonManager.exit();
|
||||
walletManager.closeWallet();
|
||||
Qt.quit();
|
||||
|
||||
closeWallet(Qt.quit);
|
||||
}
|
||||
|
||||
function onWalletCheckUpdatesComplete(update) {
|
||||
@@ -2182,8 +2018,8 @@ ApplicationWindow {
|
||||
|
||||
// reset label text. othewise potential privacy leak showing unlock time when switching wallets
|
||||
function clearMoneroCardLabelText(){
|
||||
leftPanel.minutesToUnlockTxt = qsTr("Unlocked balance")
|
||||
leftPanel.balanceLabelText = qsTr("Balance")
|
||||
leftPanel.balanceString = "?.??"
|
||||
leftPanel.balanceFiatString = "?.??"
|
||||
}
|
||||
|
||||
// some fields need an extra nudge when changing languages
|
||||
@@ -2201,6 +2037,7 @@ ApplicationWindow {
|
||||
function checkInUserActivity() {
|
||||
if(rootItem.state !== "normal") return;
|
||||
if(!persistentSettings.lockOnUserInActivity) return;
|
||||
if(passwordDialog.visible) return;
|
||||
|
||||
// prompt password after X seconds of inactivity
|
||||
var epoch = Math.floor((new Date).getTime() / 1000);
|
||||
@@ -2231,11 +2068,22 @@ ApplicationWindow {
|
||||
}
|
||||
|
||||
function changeWalletMode(mode){
|
||||
appWindow.disconnectedEpoch = 0;
|
||||
appWindow.walletMode = mode;
|
||||
persistentSettings.walletMode = mode;
|
||||
persistentSettings.useRemoteNode = mode === 0 ? true : false;
|
||||
applyWalletMode(mode);
|
||||
}
|
||||
|
||||
console.log("walletMode changed: " + (mode === 0 ? "simple": mode === 1 ? "simple (bootstrap)" : "Advanced"));
|
||||
function applyWalletMode(mode){
|
||||
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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# qml components require at least QT 5.7.0
|
||||
lessThan (QT_MAJOR_VERSION, 5) | lessThan (QT_MINOR_VERSION, 7) {
|
||||
error("Can't build with Qt $${QT_VERSION}. Use at least Qt 5.7.0")
|
||||
# qml components require at least QT 5.9.7
|
||||
lessThan (QT_MAJOR_VERSION, 5) | lessThan (QT_MINOR_VERSION, 9) {
|
||||
error("Can't build with Qt $${QT_VERSION}. Use at least Qt 5.9.7")
|
||||
}
|
||||
|
||||
TEMPLATE = app
|
||||
@@ -16,10 +16,21 @@ packagesExist(libusb-1.0) {
|
||||
packagesExist(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_LFLAGS += -fstack-protector -fstack-protector-strong
|
||||
}
|
||||
|
||||
!win32 {
|
||||
packagesExist(protobuf) {
|
||||
PKGCONFIG += protobuf
|
||||
}
|
||||
@@ -65,10 +76,12 @@ HEADERS += \
|
||||
MainApp.h \
|
||||
src/qt/FutureScheduler.h \
|
||||
src/qt/ipc.h \
|
||||
src/qt/mime.h \
|
||||
src/qt/KeysFiles.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 \
|
||||
filter.cpp \
|
||||
@@ -99,10 +112,11 @@ SOURCES += main.cpp \
|
||||
MainApp.cpp \
|
||||
src/qt/FutureScheduler.cpp \
|
||||
src/qt/ipc.cpp \
|
||||
src/qt/mime.cpp \
|
||||
src/qt/KeysFiles.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) {
|
||||
HEADERS -= src/zxcvbn-c/zxcvbn.h
|
||||
@@ -139,25 +153,25 @@ ios:arm64 {
|
||||
LIBS += \
|
||||
-L$$PWD/../ofxiOSBoost/build/libs/boost/lib/arm64 \
|
||||
}
|
||||
|
||||
LIBS_COMMON = \
|
||||
-lwallet_merged \
|
||||
-llmdb \
|
||||
-lepee \
|
||||
-lunbound \
|
||||
-lsodium \
|
||||
-leasylogging \
|
||||
-lrandomx
|
||||
|
||||
!ios:!android {
|
||||
LIBS += -L$$WALLET_ROOT/lib \
|
||||
-lwallet_merged \
|
||||
-llmdb \
|
||||
-lepee \
|
||||
-lunbound \
|
||||
-lsodium \
|
||||
-leasylogging
|
||||
LIBS += -L$$WALLET_ROOT/lib \
|
||||
$$LIBS_COMMON
|
||||
}
|
||||
|
||||
android {
|
||||
message("Host is Android")
|
||||
LIBS += -L$$WALLET_ROOT/lib \
|
||||
-lwallet_merged \
|
||||
-llmdb \
|
||||
-lepee \
|
||||
-lunbound \
|
||||
-lsodium \
|
||||
-leasylogging
|
||||
$$LIBS_COMMON
|
||||
}
|
||||
|
||||
|
||||
@@ -172,12 +186,7 @@ ios {
|
||||
QMAKE_IOS_DEVICE_ARCHS = arm64
|
||||
CONFIG += arm64
|
||||
LIBS += -L$$WALLET_ROOT/lib-ios \
|
||||
-lwallet_merged \
|
||||
-llmdb \
|
||||
-lepee \
|
||||
-lunbound \
|
||||
-lsodium \
|
||||
-leasylogging
|
||||
$$LIBS_COMMON
|
||||
|
||||
LIBS+= \
|
||||
-L$$PWD/../OpenSSL-for-iPhone/lib \
|
||||
@@ -284,6 +293,7 @@ win32 {
|
||||
-licudt \
|
||||
-licutu \
|
||||
-liconv \
|
||||
-lstdc++ \
|
||||
-lpthread \
|
||||
-lsetupapi \
|
||||
-lssl \
|
||||
@@ -339,7 +349,8 @@ linux {
|
||||
if(!android) {
|
||||
LIBS+= \
|
||||
-Wl,-Bdynamic \
|
||||
-lGL
|
||||
-lGL \
|
||||
-lX11
|
||||
}
|
||||
# currently monero has an issue with "static" build and linunwind-dev,
|
||||
# so we link libunwind-dev only for non-Ubuntu distros
|
||||
@@ -359,6 +370,8 @@ macx {
|
||||
# message("using static libraries")
|
||||
# LIBS+= -Wl,-Bstatic
|
||||
# }
|
||||
QT += macextras
|
||||
OBJECTIVE_SOURCES += src/qt/macoshelper.mm
|
||||
LIBS+= \
|
||||
-L/usr/local/lib \
|
||||
-L/usr/local/opt/openssl/lib \
|
||||
@@ -372,6 +385,7 @@ macx {
|
||||
-lboost_chrono \
|
||||
-lboost_program_options \
|
||||
-framework CoreFoundation \
|
||||
-framework AppKit \
|
||||
-lhidapi \
|
||||
-lssl \
|
||||
-lsodium \
|
||||
@@ -490,6 +504,9 @@ DISTFILES += \
|
||||
notes.txt \
|
||||
monero/src/wallet/CMakeLists.txt
|
||||
|
||||
VERSION = $$cat('version.js', lines)
|
||||
VERSION = $$find(VERSION, 'GUI_VERSION')
|
||||
VERSION = $$replace(VERSION, '.*(\d+\.\d+\.\d+\.\d+).*', '\1')
|
||||
|
||||
# windows application icon
|
||||
RC_ICONS = images/appicon.ico
|
||||
|
||||
35
oshelper.cpp
@@ -31,6 +31,20 @@
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
#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)
|
||||
{
|
||||
@@ -58,6 +72,27 @@ bool OSHelper::removeTemporaryWallet(const QString &fileName) const
|
||||
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
|
||||
{
|
||||
return QDir::tempPath();
|
||||
|
||||
@@ -42,6 +42,7 @@ public:
|
||||
Q_INVOKABLE QString temporaryFilename() const;
|
||||
Q_INVOKABLE QString temporaryPath() const;
|
||||
Q_INVOKABLE bool removeTemporaryWallet(const QString &walletName) const;
|
||||
Q_INVOKABLE bool isCapsLock() const;
|
||||
|
||||
signals:
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ Rectangle {
|
||||
/* main layout */
|
||||
ColumnLayout {
|
||||
id: mainLayout
|
||||
anchors.margins: (isMobile)? 17 : 20
|
||||
anchors.margins: 20
|
||||
anchors.topMargin: 40
|
||||
|
||||
anchors.left: parent.left
|
||||
@@ -101,8 +101,7 @@ Rectangle {
|
||||
id: balanceAll
|
||||
font.family: MoneroComponents.Style.fontMonoRegular.name;
|
||||
font.pixelSize: 16
|
||||
color: MoneroComponents.Style.dimmedFontColor
|
||||
themeTransition: false
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
|
||||
MouseArea {
|
||||
hoverEnabled: true
|
||||
@@ -135,8 +134,7 @@ Rectangle {
|
||||
id: unlockedBalanceAll
|
||||
font.family: MoneroComponents.Style.fontMonoRegular.name;
|
||||
font.pixelSize: 16
|
||||
color: MoneroComponents.Style.dimmedFontColor
|
||||
themeTransition: false
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
|
||||
MouseArea {
|
||||
hoverEnabled: true
|
||||
@@ -177,7 +175,7 @@ Rectangle {
|
||||
ListView {
|
||||
id: subaddressAccountListView
|
||||
Layout.fillWidth: true
|
||||
anchors.fill: parent
|
||||
Layout.fillHeight: true
|
||||
clip: true
|
||||
boundsBehavior: ListView.StopAtBounds
|
||||
interactive: false
|
||||
@@ -365,6 +363,7 @@ Rectangle {
|
||||
appWindow.currentWallet.subaddressAccount.addRow(inputDialog.inputText)
|
||||
appWindow.currentWallet.switchSubaddressAccount(appWindow.currentWallet.numSubaddressAccounts() - 1)
|
||||
current_subaddress_account_table_index = appWindow.currentWallet.numSubaddressAccounts() - 1
|
||||
subaddressAccountListView.currentIndex = current_subaddress_account_table_index
|
||||
appWindow.onWalletUpdate();
|
||||
}
|
||||
inputDialog.onRejectedCallback = null;
|
||||
|
||||
@@ -52,7 +52,7 @@ Rectangle {
|
||||
|
||||
ColumnLayout {
|
||||
id: mainLayout
|
||||
anchors.margins: (isMobile)? 17 : 20
|
||||
anchors.margins: 20
|
||||
anchors.topMargin: 40
|
||||
|
||||
anchors.left: parent.left
|
||||
@@ -145,7 +145,7 @@ Rectangle {
|
||||
ListView {
|
||||
id: addressBookListView
|
||||
Layout.fillWidth: true
|
||||
anchors.fill: parent
|
||||
Layout.fillHeight: true
|
||||
clip: true
|
||||
boundsBehavior: ListView.StopAtBounds
|
||||
interactive: false
|
||||
@@ -325,8 +325,8 @@ Rectangle {
|
||||
wrapMode: Text.WrapAnywhere
|
||||
addressValidation: true
|
||||
pasteButton: true
|
||||
onPaste: function(clipboardText) {
|
||||
const parsed = walletManager.parse_uri_to_object(clipboardText);
|
||||
onTextChanged: {
|
||||
const parsed = walletManager.parse_uri_to_object(addressLine.text);
|
||||
if (!parsed.error) {
|
||||
addressLine.text = parsed.address;
|
||||
descriptionLine.text = parsed.tx_description;
|
||||
|
||||
@@ -49,9 +49,9 @@ Rectangle {
|
||||
property var model
|
||||
property int sideMargin: 50
|
||||
property var initialized: false
|
||||
property int txMax: 5
|
||||
property int txMax: Math.max(5, ((appWindow.height - 250) / 60))
|
||||
property int txOffset: 0
|
||||
property int txPage: (txOffset / 5) + 1
|
||||
property int txPage: (txOffset / txMax) + 1
|
||||
property int txCount: 0
|
||||
property var sortSearchString: null
|
||||
property bool sortDirection: true // true = desc, false = asc
|
||||
@@ -67,6 +67,8 @@ Rectangle {
|
||||
|
||||
color: "transparent"
|
||||
|
||||
onTxMaxChanged: root.updateDisplay(root.txOffset, root.txMax);
|
||||
|
||||
ColumnLayout {
|
||||
id: pageRoot
|
||||
anchors.topMargin: 40
|
||||
@@ -249,7 +251,6 @@ Rectangle {
|
||||
font.pixelSize: 15
|
||||
text: qsTr("Blockheight") + translationManager.emptyString
|
||||
color: root.sortBy === "blockheight" ? MoneroComponents.Style.defaultFontColor : MoneroComponents.Style.dimmedFontColor
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
themeTransition: false
|
||||
}
|
||||
|
||||
@@ -310,7 +311,6 @@ Rectangle {
|
||||
text: qsTr("Date") + translationManager.emptyString
|
||||
color: root.sortBy === "timestamp" ? MoneroComponents.Style.defaultFontColor : MoneroComponents.Style.dimmedFontColor
|
||||
themeTransition: false
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
MoneroEffects.ImageMask {
|
||||
@@ -370,7 +370,6 @@ Rectangle {
|
||||
text: qsTr("Amount") + translationManager.emptyString
|
||||
color: root.sortBy === "amount" ? MoneroComponents.Style.defaultFontColor : MoneroComponents.Style.dimmedFontColor
|
||||
themeTransition: false
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
MoneroEffects.ImageMask {
|
||||
@@ -940,7 +939,7 @@ Rectangle {
|
||||
anchors.leftMargin: 10
|
||||
text: FontAwesome.productHunt
|
||||
small: true
|
||||
label.font.family: FontAwesome.fontFamily
|
||||
label.font.family: FontAwesome.fontFamilyBrands
|
||||
fontSize: 18
|
||||
width: 36
|
||||
|
||||
@@ -1343,13 +1342,14 @@ Rectangle {
|
||||
root.updateDisplay(root.txOffset, root.txMax);
|
||||
}
|
||||
|
||||
function reset() {
|
||||
function reset(keepDate) {
|
||||
root.txOffset = 0;
|
||||
root.txMax = 5;
|
||||
|
||||
if (typeof root.model !== 'undefined' && root.model != null) {
|
||||
root.model.dateFromFilter = "2014-04-18" // genesis block
|
||||
root.model.dateToFilter = "9999-09-09" // fix before september 9999
|
||||
if (!keepDate) {
|
||||
root.model.dateFromFilter = "2014-04-18" // genesis block
|
||||
root.model.dateToFilter = "9999-09-09" // fix before september 9999
|
||||
}
|
||||
// negative values disable filters here;
|
||||
root.model.amountFromFilter = -1;
|
||||
root.model.amountToFilter = -1;
|
||||
@@ -1361,8 +1361,9 @@ Rectangle {
|
||||
// applying filters
|
||||
root.txData = JSON.parse(JSON.stringify(root.txModelData)); // deepcopy
|
||||
|
||||
var fromDate = fromDatePicker.currentDate.getTime() / 1000;
|
||||
var toDate = toDatePicker.currentDate.getTime() / 1000;
|
||||
const timezoneOffset = new Date().getTimezoneOffset() * 60;
|
||||
var fromDate = Math.floor(fromDatePicker.currentDate.getTime() / 86400000) * 86400 + timezoneOffset;
|
||||
var toDate = (Math.floor(toDatePicker.currentDate.getTime() / 86400000) + 1) * 86400 + timezoneOffset;
|
||||
|
||||
var txs = [];
|
||||
for (var i = 0; i < root.txData.length; i++){
|
||||
@@ -1387,6 +1388,8 @@ Rectangle {
|
||||
txs.push(item);
|
||||
} else if(item.blockheight.toString().startsWith(root.sortSearchString)) {
|
||||
txs.push(item);
|
||||
} else if(item.tx_note.toLowerCase().indexOf(root.sortSearchString.toLowerCase()) !== -1) {
|
||||
txs.push(item);
|
||||
} else if (item.hash.startsWith(root.sortSearchString)){
|
||||
txs.push(item);
|
||||
}
|
||||
@@ -1580,9 +1583,9 @@ Rectangle {
|
||||
elem.parent.text = txKey ? txKey : '-';
|
||||
elem.parent.state = 'ready';
|
||||
});
|
||||
} else {
|
||||
toClipboard(elem.parent.text);
|
||||
}
|
||||
|
||||
toClipboard(elem.parent.text);
|
||||
}
|
||||
|
||||
function showTxDetails(hash, paymentId, destinations, subaddrAccount, subaddrIndex){
|
||||
@@ -1704,6 +1707,6 @@ Rectangle {
|
||||
|
||||
function onPageClosed(){
|
||||
root.initialized = false;
|
||||
root.reset();
|
||||
root.reset(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
|
||||
anchors.margins: (isMobile)? 17 : 20
|
||||
anchors.margins: 20
|
||||
anchors.topMargin: 40
|
||||
|
||||
spacing: 30
|
||||
@@ -116,11 +116,11 @@ Rectangle {
|
||||
|
||||
MoneroComponents.LineEdit {
|
||||
Layout.fillWidth: true
|
||||
id: walletCreationHeight
|
||||
readOnly: true
|
||||
copyButton: true
|
||||
labelText: qsTr("Block #") + translationManager.emptyString
|
||||
fontSize: 16
|
||||
text: currentWallet.walletCreationHeight
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,7 +251,7 @@ Rectangle {
|
||||
onClicked: {
|
||||
loadPage("Settings")
|
||||
}
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
width: 135
|
||||
}
|
||||
}
|
||||
@@ -261,6 +261,7 @@ Rectangle {
|
||||
function onPageCompleted() {
|
||||
console.log("keys page loaded");
|
||||
|
||||
walletCreationHeight.text = currentWallet.walletCreationHeight
|
||||
secretViewKey.text = currentWallet.secretViewKey
|
||||
publicViewKey.text = currentWallet.publicViewKey
|
||||
secretSpendKey.text = (!currentWallet.viewOnly) ? currentWallet.secretSpendKey : ""
|
||||
|
||||
@@ -41,7 +41,7 @@ Rectangle {
|
||||
ColumnLayout {
|
||||
id: mainLayout
|
||||
Layout.fillWidth: true
|
||||
anchors.margins: (isMobile)? 17 : 20
|
||||
anchors.margins: 20
|
||||
anchors.topMargin: 40
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
|
||||
@@ -31,6 +31,7 @@ import QtQuick.Controls 2.0
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQuick.Dialogs 1.2
|
||||
import FontAwesome 1.0
|
||||
|
||||
import "../components" as MoneroComponents
|
||||
import "../components/effects/" as MoneroEffects
|
||||
@@ -65,7 +66,7 @@ Rectangle {
|
||||
/* main layout */
|
||||
ColumnLayout {
|
||||
id: mainLayout
|
||||
anchors.margins: (isMobile)? 17 : 20
|
||||
anchors.margins: 20
|
||||
anchors.topMargin: 40
|
||||
|
||||
anchors.left: parent.left
|
||||
@@ -101,7 +102,7 @@ Rectangle {
|
||||
ListView {
|
||||
id: subaddressListView
|
||||
Layout.fillWidth: true
|
||||
anchors.fill: parent
|
||||
Layout.fillHeight: true
|
||||
clip: true
|
||||
boundsBehavior: ListView.StopAtBounds
|
||||
interactive: false
|
||||
@@ -256,6 +257,7 @@ Rectangle {
|
||||
inputDialog.onAcceptedCallback = function() {
|
||||
appWindow.currentWallet.subaddress.addRow(appWindow.currentWallet.currentSubaddressAccount, inputDialog.inputText)
|
||||
current_subaddress_table_index = appWindow.currentWallet.numSubaddresses(appWindow.currentWallet.currentSubaddressAccount) - 1
|
||||
subaddressListView.currentIndex = current_subaddress_table_index
|
||||
}
|
||||
inputDialog.onRejectedCallback = null;
|
||||
inputDialog.open()
|
||||
@@ -308,6 +310,20 @@ Rectangle {
|
||||
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,
|
||||
'');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ Rectangle {
|
||||
ColumnLayout {
|
||||
id: mainLayout
|
||||
Layout.fillWidth: true
|
||||
anchors.margins: (isMobile)? 17 : 20
|
||||
anchors.margins: 20
|
||||
anchors.topMargin: 40
|
||||
|
||||
anchors.left: parent.left
|
||||
@@ -296,7 +296,7 @@ Rectangle {
|
||||
|
||||
GridLayout{
|
||||
Layout.topMargin: 12
|
||||
columns: (isMobile) ? 1 : 2
|
||||
columns: 2
|
||||
columnSpacing: 32
|
||||
|
||||
ColumnLayout {
|
||||
@@ -368,7 +368,7 @@ Rectangle {
|
||||
|
||||
GridLayout {
|
||||
columnSpacing: 20
|
||||
columns: (isMobile) ? 1 : 2
|
||||
columns: 2
|
||||
|
||||
MoneroComponents.CheckBox {
|
||||
id: segregatePreForkOutputs
|
||||
@@ -405,7 +405,7 @@ Rectangle {
|
||||
id: segregationHeightRow
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 17
|
||||
columns: (isMobile) ? 1 : 2
|
||||
columns: 2
|
||||
columnSpacing: 32
|
||||
|
||||
MoneroComponents.LineEdit {
|
||||
|
||||
@@ -88,7 +88,7 @@ Rectangle {
|
||||
ColumnLayout {
|
||||
id: mainLayout
|
||||
Layout.fillWidth: true
|
||||
anchors.margins: (isMobile)? 17 : 20
|
||||
anchors.margins: 20
|
||||
anchors.topMargin: 40
|
||||
|
||||
anchors.left: parent.left
|
||||
|
||||
@@ -56,7 +56,7 @@ Rectangle {
|
||||
property bool showAdvanced: false
|
||||
// @TODO: remove after pid removal hardfork
|
||||
property bool warningLongPidTransfer: false
|
||||
property bool warningLongPidDescription: false
|
||||
property bool warningLongPidDescription: descriptionLine.text.match(/^[0-9a-f]{64}$/i)
|
||||
|
||||
Clipboard { id: clipboard }
|
||||
|
||||
@@ -123,7 +123,7 @@ Rectangle {
|
||||
|
||||
ColumnLayout {
|
||||
id: pageRoot
|
||||
anchors.margins: (isMobile)? 17 : 20
|
||||
anchors.margins: 20
|
||||
anchors.topMargin: 40
|
||||
|
||||
anchors.left: parent.left
|
||||
@@ -143,8 +143,16 @@ 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 {
|
||||
columns: (isMobile || !(appWindow.walletMode >= 2)) ? 1 : 2
|
||||
columns: appWindow.walletMode < 2 ? 1 : 2
|
||||
Layout.fillWidth: true
|
||||
columnSpacing: 32
|
||||
|
||||
@@ -160,6 +168,10 @@ Rectangle {
|
||||
labelText: qsTr("<style type='text/css'>a {text-decoration: none; color: #858585; font-size: 14px;}</style>\
|
||||
Amount <font size='2'> ( </font> <a href='#'>Change account</a><font size='2'> )</font>")
|
||||
+ translationManager.emptyString
|
||||
copyButton: persistentSettings.fiatPriceEnabled
|
||||
copyButtonText: fiatApiCurrencySymbol() + " ~" + fiatApiConvertToFiat(amountLine.text)
|
||||
copyButtonEnabled: false
|
||||
|
||||
onLabelLinkActivated: {
|
||||
middlePanel.accountView.selectAndSend = true;
|
||||
appWindow.showPageRequest("Account")
|
||||
@@ -203,10 +215,10 @@ Rectangle {
|
||||
id: priorityModelV5
|
||||
|
||||
ListElement { column1: qsTr("Automatic") ; column2: ""; priority: 0}
|
||||
ListElement { column1: qsTr("Slow (x0.25 fee)") ; column2: ""; priority: 1}
|
||||
ListElement { column1: qsTr("Slow (x0.2 fee)") ; column2: ""; priority: 1}
|
||||
ListElement { column1: qsTr("Normal (x1 fee)") ; column2: ""; priority: 2 }
|
||||
ListElement { column1: qsTr("Fast (x5 fee)") ; column2: ""; priority: 3 }
|
||||
ListElement { column1: qsTr("Fastest (x41.5 fee)") ; column2: ""; priority: 4 }
|
||||
ListElement { column1: qsTr("Fastest (x200 fee)") ; column2: ""; priority: 4 }
|
||||
}
|
||||
|
||||
StandardDropdown {
|
||||
@@ -249,20 +261,15 @@ Rectangle {
|
||||
appWindow.showPageRequest("AddressBook");
|
||||
}
|
||||
pasteButton: true
|
||||
onPaste: function(clipboardText) {
|
||||
const parsed = walletManager.parse_uri_to_object(clipboardText);
|
||||
onTextChanged: {
|
||||
const parsed = walletManager.parse_uri_to_object(text);
|
||||
if (!parsed.error) {
|
||||
addressLine.text = parsed.address;
|
||||
setPaymentId(parsed.payment_id);
|
||||
amountLine.text = parsed.amount;
|
||||
setDescription(parsed.tx_description);
|
||||
} else {
|
||||
addressLine.text = clipboardText;
|
||||
}
|
||||
}
|
||||
onTextChanged: {
|
||||
// @TODO: remove after pid removal hardfork
|
||||
warningLongPidTransfer = !persistentSettings.showPid && isLongPidService(text)
|
||||
warningLongPidTransfer = isLongPidService(text);
|
||||
}
|
||||
inlineButton.text: FontAwesome.qrcode
|
||||
inlineButton.fontPixelSize: 22
|
||||
@@ -323,6 +330,12 @@ 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 {
|
||||
spacing: 15
|
||||
|
||||
@@ -352,7 +365,7 @@ Rectangle {
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
visible: appWindow.persistentSettings.showPid || paymentIdCheckbox.checked
|
||||
visible: paymentIdCheckbox.checked
|
||||
// @TODO: remove after pid removal hardfork
|
||||
CheckBox {
|
||||
id: paymentIdCheckbox
|
||||
@@ -375,6 +388,7 @@ Rectangle {
|
||||
id: paymentIdLine
|
||||
fontBold: true
|
||||
placeholderText: qsTr("64 hexadecimal characters") + translationManager.emptyString
|
||||
readOnly: true
|
||||
Layout.fillWidth: true
|
||||
wrapMode: Text.WrapAnywhere
|
||||
addressValidation: false
|
||||
@@ -386,8 +400,10 @@ Rectangle {
|
||||
MoneroComponents.WarningBox {
|
||||
// @TODO: remove after pid removal hardfork
|
||||
id: paymentIdWarningBox
|
||||
text: qsTr("You can enable transfers with payment ID on the settings page.") + translationManager.emptyString;
|
||||
visible: !persistentSettings.showPid && (warningLongPidTransfer || warningLongPidDescription)
|
||||
text: qsTr("Long payment IDs are obsolete. \
|
||||
Long payment IDs were not encrypted on the blockchain and would harm your privacy. \
|
||||
If the party you're sending to still requires a long payment ID, please notify them.") + translationManager.emptyString;
|
||||
visible: warningLongPidTransfer || paymentIdCheckbox.checked
|
||||
}
|
||||
|
||||
MoneroComponents.WarningBox {
|
||||
@@ -443,7 +459,7 @@ Rectangle {
|
||||
anchors.top: pageRoot.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.margins: (isMobile)? 17 : 20
|
||||
anchors.margins: 20
|
||||
anchors.topMargin: 32
|
||||
spacing: 26
|
||||
enabled: !viewOnly || pageRoot.enabled
|
||||
@@ -462,7 +478,7 @@ Rectangle {
|
||||
|
||||
GridLayout {
|
||||
visible: persistentSettings.transferShowAdvanced && appWindow.walletMode >= 2
|
||||
columns: (isMobile) ? 2 : 6
|
||||
columns: 6
|
||||
|
||||
StandardButton {
|
||||
id: sweepUnmixableButton
|
||||
@@ -740,7 +756,8 @@ Rectangle {
|
||||
|
||||
// Currently opened wallet is not view-only
|
||||
if(appWindow.viewOnly){
|
||||
root.sendButtonWarning = qsTr("Wallet is view-only and sends are not possible.") + translationManager.emptyString;
|
||||
root.sendButtonWarning = qsTr("Wallet is view-only and sends are not possible. Unless key images are imported, " +
|
||||
"the balance reflects only incoming but not outgoing transactions.") + translationManager.emptyString;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -761,6 +778,11 @@ Rectangle {
|
||||
root.sendButtonWarning = qsTr("Transaction information is incorrect.") + translationManager.emptyString;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (paymentIdWarningBox.visible) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ Rectangle {
|
||||
/* main layout */
|
||||
ColumnLayout {
|
||||
id: mainLayout
|
||||
anchors.margins: (isMobile)? 17 : 20
|
||||
anchors.margins: 20
|
||||
anchors.topMargin: 40
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
|
||||
@@ -33,8 +33,6 @@ Item {
|
||||
property var hiddenAmounts: []
|
||||
|
||||
function onPageCompleted() {
|
||||
appWindow.hideMenu();
|
||||
|
||||
// prepare tracking
|
||||
trackingCheckbox.checked = root.enableTracking
|
||||
root.update();
|
||||
@@ -56,8 +54,6 @@ Item {
|
||||
timer.running = false
|
||||
root.enableTracking = false
|
||||
trackingModel.clear()
|
||||
|
||||
appWindow.showMenu();
|
||||
}
|
||||
|
||||
Image {
|
||||
@@ -93,9 +89,8 @@ Item {
|
||||
anchors.right: parent.right
|
||||
|
||||
Item {
|
||||
height: 220
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
Layout.preferredHeight: 220
|
||||
Layout.fillWidth: true
|
||||
|
||||
Rectangle {
|
||||
id: tracker
|
||||
@@ -258,8 +253,7 @@ Item {
|
||||
|
||||
Item {
|
||||
Layout.preferredHeight: 40
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
Layout.fillWidth: true
|
||||
|
||||
Item {
|
||||
width: (parent.width - qrImg.width) - (50)
|
||||
@@ -461,7 +455,7 @@ Item {
|
||||
width: 220
|
||||
source: "qrc:///images/merchant/input_box.png"
|
||||
|
||||
TextField {
|
||||
MoneroComponents.Input {
|
||||
id: amountToReceive
|
||||
topPadding: 0
|
||||
leftPadding: 10
|
||||
@@ -524,8 +518,7 @@ Item {
|
||||
Item {
|
||||
Layout.topMargin: 32
|
||||
Layout.preferredHeight: 40
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
Layout.fillWidth: true
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 16
|
||||
@@ -630,7 +623,7 @@ Item {
|
||||
in_txpool = true;
|
||||
} else {
|
||||
if (blockchainHeight == null)
|
||||
blockchainHeight = appWindow.currentWallet.blockChainHeight()
|
||||
blockchainHeight = walletManager.blockchainHeight()
|
||||
confirmations = blockchainHeight - blockHeight - 1
|
||||
displayAmount = model.data(idx, TransactionHistoryModel.TransactionDisplayAmountRole);
|
||||
}
|
||||
|
||||
@@ -4,38 +4,55 @@ import QtGraphicalEffects 1.0
|
||||
|
||||
import "../../components" as MoneroComponents
|
||||
|
||||
RowLayout {
|
||||
Item {
|
||||
id: root
|
||||
spacing: 10
|
||||
property bool checked: false;
|
||||
property alias text: content.text
|
||||
signal changed;
|
||||
|
||||
Rectangle {
|
||||
id: checkbox
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
implicitHeight: 22
|
||||
width: 22
|
||||
radius: 5
|
||||
width: checkBoxLayout.width
|
||||
height: 22
|
||||
|
||||
Image {
|
||||
id: imageChecked
|
||||
visible: root.checked
|
||||
anchors.centerIn: parent
|
||||
source: "qrc:///images/uncheckedIcon.png"
|
||||
RowLayout {
|
||||
id: checkBoxLayout
|
||||
spacing: 10
|
||||
|
||||
Item {
|
||||
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 {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
@@ -46,16 +63,4 @@ RowLayout {
|
||||
changed();
|
||||
}
|
||||
}
|
||||
|
||||
DropShadow {
|
||||
anchors.fill: source
|
||||
cached: true
|
||||
horizontalOffset: 3
|
||||
verticalOffset: 3
|
||||
radius: 8.0
|
||||
samples: 16
|
||||
color: "#20000000"
|
||||
smooth: true
|
||||
source: checkbox
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ Rectangle {
|
||||
property bool showCloseButton: true
|
||||
|
||||
height: {
|
||||
if(!persistentSettings.customDecorations || isMobile) return 0;
|
||||
if(!persistentSettings.customDecorations) return 0;
|
||||
return 50;
|
||||
}
|
||||
|
||||
|
||||
@@ -61,9 +61,7 @@ Rectangle {
|
||||
property string borderColor: MoneroComponents.Style.blackTheme ? "#808080" : "#B9B9B9"
|
||||
property int textMargin: {
|
||||
// left-right margins for a given cell
|
||||
if(isMobile){
|
||||
return 10;
|
||||
} else if(appWindow.width < 890){
|
||||
if(appWindow.width < 890){
|
||||
return 32;
|
||||
} else {
|
||||
return 64;
|
||||
|
||||
@@ -57,7 +57,7 @@ Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
anchors.margins: (isMobile)? 17 : 20
|
||||
anchors.margins: 20
|
||||
anchors.topMargin: 0
|
||||
spacing: 30
|
||||
|
||||
@@ -208,10 +208,11 @@ Rectangle {
|
||||
confirmationDialog.icon = StandardIcon.Question
|
||||
confirmationDialog.cancelText = qsTr("Cancel")
|
||||
confirmationDialog.onAcceptedCallback = function() {
|
||||
walletManager.closeWallet();
|
||||
walletManager.clearWalletCache(persistentSettings.wallet_path);
|
||||
walletManager.openWalletAsync(persistentSettings.wallet_path, appWindow.walletPassword,
|
||||
persistentSettings.nettype, persistentSettings.kdfRounds);
|
||||
appWindow.closeWallet(function() {
|
||||
walletManager.clearWalletCache(persistentSettings.wallet_path);
|
||||
walletManager.openWalletAsync(persistentSettings.wallet_path, appWindow.walletPassword,
|
||||
persistentSettings.nettype, persistentSettings.kdfRounds);
|
||||
});
|
||||
}
|
||||
|
||||
confirmationDialog.onRejectedCallback = null;
|
||||
@@ -325,6 +326,41 @@ Rectangle {
|
||||
font.pixelSize: 14
|
||||
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
|
||||
|
||||
@@ -47,12 +47,11 @@ Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
anchors.margins: (isMobile)? 17 : 20
|
||||
anchors.margins: 20
|
||||
anchors.topMargin: 0
|
||||
spacing: 6
|
||||
|
||||
MoneroComponents.CheckBox {
|
||||
visible: !isMobile
|
||||
id: customDecorationsCheckBox
|
||||
checked: persistentSettings.customDecorations
|
||||
onClicked: Windows.setCustomWindowDecorations(checked)
|
||||
@@ -60,7 +59,6 @@ Rectangle {
|
||||
}
|
||||
|
||||
MoneroComponents.CheckBox {
|
||||
visible: !isMobile
|
||||
id: hideBalanceCheckBox
|
||||
checked: persistentSettings.hideBalance
|
||||
onClicked: {
|
||||
@@ -70,20 +68,11 @@ Rectangle {
|
||||
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 {
|
||||
id: themeCheckbox
|
||||
checked: !MoneroComponents.Style.blackTheme
|
||||
text: qsTr("Light theme") + translationManager.emptyString
|
||||
toggleOnClick: false
|
||||
onClicked: {
|
||||
MoneroComponents.Style.blackTheme = !MoneroComponents.Style.blackTheme;
|
||||
persistentSettings.blackTheme = MoneroComponents.Style.blackTheme;
|
||||
@@ -91,7 +80,6 @@ Rectangle {
|
||||
}
|
||||
|
||||
MoneroComponents.CheckBox {
|
||||
visible: !isMobile
|
||||
id: userInActivityCheckbox
|
||||
checked: persistentSettings.lockOnUserInActivity
|
||||
onClicked: persistentSettings.lockOnUserInActivity = !persistentSettings.lockOnUserInActivity
|
||||
@@ -267,14 +255,6 @@ Rectangle {
|
||||
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 {
|
||||
|
||||
@@ -47,7 +47,7 @@ Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
anchors.margins: (isMobile)? 17 : 20
|
||||
anchors.margins: 20
|
||||
anchors.topMargin: 0
|
||||
spacing: 10
|
||||
|
||||
@@ -216,7 +216,11 @@ Rectangle {
|
||||
onAccepted: {
|
||||
if(text.length > 0) {
|
||||
consoleArea.logCommand(">>> " + text)
|
||||
daemonManager.sendCommand(text, currentWallet.nettype);
|
||||
daemonManager.sendCommandAsync(text.split(" "), currentWallet.nettype, function(result) {
|
||||
if (!result) {
|
||||
appWindow.showStatusMessage(qsTr("Failed to send command"), 3);
|
||||
}
|
||||
});
|
||||
}
|
||||
text = ""
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ Rectangle{
|
||||
/* main layout */
|
||||
ColumnLayout {
|
||||
id: root
|
||||
anchors.margins: (isMobile)? 17 : 20
|
||||
anchors.margins: 20
|
||||
anchors.topMargin: 0
|
||||
|
||||
anchors.left: parent.left
|
||||
@@ -96,17 +96,13 @@ Rectangle{
|
||||
anchors.leftMargin: 16
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
MoneroEffects.ImageMask {
|
||||
height: 27
|
||||
width: 27
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
fontAwesomeFallbackIcon: FontAwesome.shield
|
||||
fontAwesomeFallbackSize: 26
|
||||
image: "qrc:///images/settings_local.svg"
|
||||
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
opacity: MoneroComponents.Style.blackTheme ? 1.0 : 0.8
|
||||
MoneroComponents.Label {
|
||||
fontSize: 32
|
||||
text: FontAwesome.home
|
||||
fontFamily: FontAwesome.fontFamilySolid
|
||||
anchors.centerIn: parent
|
||||
fontColor: MoneroComponents.Style.defaultFontColor
|
||||
styleName: "Solid"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,16 +198,13 @@ Rectangle{
|
||||
anchors.leftMargin: 16
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
MoneroEffects.ImageMask {
|
||||
height: 29
|
||||
width: 22
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
fontAwesomeFallbackIcon: FontAwesome.cloudDownload
|
||||
fontAwesomeFallbackSize: 26
|
||||
image: "qrc:///images/settings_remote.svg"
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
opacity: MoneroComponents.Style.blackTheme ? 1.0 : 0.8
|
||||
MoneroComponents.Label {
|
||||
fontSize: 28
|
||||
text: FontAwesome.cloud
|
||||
fontFamily: FontAwesome.fontFamilySolid
|
||||
styleName: "Solid"
|
||||
anchors.centerIn: parent
|
||||
fontColor: MoneroComponents.Style.defaultFontColor
|
||||
}
|
||||
}
|
||||
|
||||
@@ -285,7 +278,7 @@ Rectangle{
|
||||
spacing: 20
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 20
|
||||
visible: !isMobile && persistentSettings.useRemoteNode
|
||||
visible: persistentSettings.useRemoteNode
|
||||
|
||||
MoneroComponents.WarningBox {
|
||||
Layout.topMargin: 26
|
||||
@@ -317,7 +310,7 @@ Rectangle{
|
||||
}
|
||||
|
||||
GridLayout {
|
||||
columns: (isMobile) ? 1 : 2
|
||||
columns: 2
|
||||
columnSpacing: 32
|
||||
|
||||
MoneroComponents.LineEdit {
|
||||
@@ -377,11 +370,11 @@ Rectangle{
|
||||
id: localNodeLayout
|
||||
spacing: 20
|
||||
Layout.topMargin: 40
|
||||
visible: !isMobile && !persistentSettings.useRemoteNode
|
||||
visible: !persistentSettings.useRemoteNode
|
||||
|
||||
MoneroComponents.StandardButton {
|
||||
small: true
|
||||
text: (appWindow.daemonRunning ? qsTr("Stop local node") : qsTr("Start daemon")) + translationManager.emptyString
|
||||
text: (appWindow.daemonRunning ? qsTr("Stop daemon") : qsTr("Start daemon")) + translationManager.emptyString
|
||||
onClicked: {
|
||||
if (appWindow.daemonRunning) {
|
||||
appWindow.stopDaemon();
|
||||
@@ -403,6 +396,7 @@ Rectangle{
|
||||
labelText: qsTr("Blockchain location") + style + qsTr(" <a href='#'> (change)</a>") + translationManager.emptyString
|
||||
placeholderText: qsTr("(default)") + translationManager.emptyString
|
||||
placeholderFontSize: 15
|
||||
readOnly: true
|
||||
text: {
|
||||
if(persistentSettings.blockchainDataDir.length > 0){
|
||||
return persistentSettings.blockchainDataDir;
|
||||
@@ -435,7 +429,7 @@ Rectangle{
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
visible: !isMobile && !persistentSettings.useRemoteNode
|
||||
visible: !persistentSettings.useRemoteNode
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
@@ -457,7 +451,11 @@ Rectangle{
|
||||
}
|
||||
}
|
||||
onEditingFinished: {
|
||||
persistentSettings.bootstrapNodeAddress = daemonAddrText ? bootstrapNodeEdit.getAddress() : "";
|
||||
if (daemonAddrText == "auto") {
|
||||
persistentSettings.bootstrapNodeAddress = daemonAddrText;
|
||||
} else {
|
||||
persistentSettings.bootstrapNodeAddress = daemonAddrText ? bootstrapNodeEdit.getAddress() : "";
|
||||
}
|
||||
console.log("setting bootstrap node to " + persistentSettings.bootstrapNodeAddress)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,314 +45,99 @@ Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
anchors.margins: (isMobile)? 17 : 20
|
||||
anchors.margins: 20
|
||||
anchors.topMargin: 0
|
||||
spacing: 0
|
||||
spacing: 8
|
||||
|
||||
Rectangle {
|
||||
// divider
|
||||
Layout.preferredHeight: 1
|
||||
Layout.fillWidth: true
|
||||
Layout.bottomMargin: 8
|
||||
color: MoneroComponents.Style.dividerColor
|
||||
opacity: MoneroComponents.Style.dividerOpacity
|
||||
}
|
||||
MoneroComponents.SettingsListItem {
|
||||
buttonText: qsTr("Close wallet") + translationManager.emptyString
|
||||
description: qsTr("Logs out of this wallet.") + translationManager.emptyString
|
||||
title: qsTr("Close this wallet") + translationManager.emptyString
|
||||
|
||||
GridLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: childrenRect.height
|
||||
columnSpacing: 0
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
spacing: 0
|
||||
|
||||
MoneroComponents.TextPlain {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 20
|
||||
Layout.topMargin: 8
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
opacity: MoneroComponents.Style.blackTheme ? 1.0 : 0.8
|
||||
font.bold: true
|
||||
font.family: MoneroComponents.Style.fontRegular.name
|
||||
font.pixelSize: 16
|
||||
text: qsTr("Close this wallet") + translationManager.emptyString
|
||||
}
|
||||
|
||||
MoneroComponents.TextPlainArea {
|
||||
color: MoneroComponents.Style.dimmedFontColor
|
||||
colorBlackTheme: MoneroComponents.Style._b_dimmedFontColor
|
||||
colorWhiteTheme: MoneroComponents.Style._w_dimmedFontColor
|
||||
width: parent.width
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: TextInput.AlignLeft
|
||||
text: qsTr("Logs out of this wallet.") + translationManager.emptyString
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.StandardButton {
|
||||
small: true
|
||||
text: qsTr("Close wallet") + translationManager.emptyString
|
||||
onClicked: {
|
||||
middlePanel.addressBookView.clearFields();
|
||||
middlePanel.transferView.clearFields();
|
||||
middlePanel.receiveView.clearFields();
|
||||
appWindow.showWizard();
|
||||
}
|
||||
width: 135
|
||||
onClicked: {
|
||||
middlePanel.addressBookView.clearFields();
|
||||
middlePanel.transferView.clearFields();
|
||||
middlePanel.receiveView.clearFields();
|
||||
appWindow.showWizard();
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
// divider
|
||||
Layout.preferredHeight: 1
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 8
|
||||
Layout.bottomMargin: 8
|
||||
color: MoneroComponents.Style.dividerColor
|
||||
opacity: MoneroComponents.Style.dividerOpacity
|
||||
}
|
||||
|
||||
GridLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: childrenRect.height
|
||||
columnSpacing: 0
|
||||
MoneroComponents.SettingsListItem {
|
||||
buttonText: qsTr("Create wallet") + translationManager.emptyString
|
||||
description: qsTr("Creates a new wallet that can only view and initiate transactions, but requires a spendable wallet to sign transactions before sending.") + translationManager.emptyString
|
||||
title: qsTr("Create a view-only wallet") + translationManager.emptyString
|
||||
visible: !appWindow.viewOnly
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
spacing: 0
|
||||
|
||||
MoneroComponents.TextPlain {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 20
|
||||
Layout.topMargin: 8
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
opacity: MoneroComponents.Style.blackTheme ? 1.0 : 0.8
|
||||
font.bold: true
|
||||
font.family: MoneroComponents.Style.fontRegular.name
|
||||
font.pixelSize: 16
|
||||
text: qsTr("Create a view-only wallet") + translationManager.emptyString
|
||||
}
|
||||
|
||||
MoneroComponents.TextPlainArea {
|
||||
color: MoneroComponents.Style.dimmedFontColor
|
||||
colorBlackTheme: MoneroComponents.Style._b_dimmedFontColor
|
||||
colorWhiteTheme: MoneroComponents.Style._w_dimmedFontColor
|
||||
width: parent.width
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: TextInput.AlignLeft
|
||||
text: qsTr("Creates a new wallet that can only view and initiate transactions, but requires a spendable wallet to sign transactions before sending.") + translationManager.emptyString
|
||||
onClicked: {
|
||||
var newPath = currentWallet.path + "_viewonly";
|
||||
if (currentWallet.createViewOnly(newPath, appWindow.walletPassword)) {
|
||||
console.log("view only wallet created in " + newPath);
|
||||
informationPopup.title = qsTr("Success") + translationManager.emptyString;
|
||||
informationPopup.text = qsTr('The view only wallet has been created with the same password as the current wallet. You can open it by closing this current wallet, clicking the "Open wallet from file" option, and selecting the view wallet in: \n%1\nYou can change the password in the wallet settings.').arg(newPath);
|
||||
informationPopup.open()
|
||||
informationPopup.onCloseCallback = null
|
||||
} else {
|
||||
informationPopup.title = qsTr("Error") + translationManager.emptyString;
|
||||
informationPopup.text = currentWallet.errorString;
|
||||
informationPopup.open()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.StandardButton {
|
||||
small: true
|
||||
text: qsTr("Create wallet") + translationManager.emptyString
|
||||
onClicked: {
|
||||
var newPath = currentWallet.path + "_viewonly";
|
||||
if (currentWallet.createViewOnly(newPath, appWindow.walletPassword)) {
|
||||
console.log("view only wallet created in " + newPath);
|
||||
informationPopup.title = qsTr("Success") + translationManager.emptyString;
|
||||
informationPopup.text = qsTr('The view only wallet has been created with the same password as the current wallet. You can open it by closing this current wallet, clicking the "Open wallet from file" option, and selecting the view wallet in: \n%1\nYou can change the password in the wallet settings.').arg(newPath);
|
||||
informationPopup.open()
|
||||
informationPopup.onCloseCallback = null
|
||||
MoneroComponents.SettingsListItem {
|
||||
buttonText: qsTr("Show seed") + translationManager.emptyString
|
||||
description: qsTr("Store this information safely to recover your wallet in the future.") + translationManager.emptyString
|
||||
title: qsTr("Show seed & keys") + translationManager.emptyString
|
||||
|
||||
onClicked: {
|
||||
Utils.showSeedPage();
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.SettingsListItem {
|
||||
buttonText: qsTr("Rescan") + translationManager.emptyString
|
||||
description: qsTr("Use this feature if you think the shown balance is not accurate.") + translationManager.emptyString
|
||||
title: qsTr("Rescan wallet balance") + translationManager.emptyString
|
||||
visible: appWindow.walletMode >= 2
|
||||
|
||||
onClicked: {
|
||||
if (!currentWallet.rescanSpent()) {
|
||||
console.error("Error: ", currentWallet.errorString);
|
||||
informationPopup.title = qsTr("Error") + translationManager.emptyString;
|
||||
informationPopup.text = qsTr("Error: ") + currentWallet.errorString
|
||||
informationPopup.icon = StandardIcon.Critical
|
||||
informationPopup.onCloseCallback = null
|
||||
informationPopup.open();
|
||||
} else {
|
||||
informationPopup.title = qsTr("Information") + translationManager.emptyString
|
||||
informationPopup.text = qsTr("Successfully rescanned spent outputs.") + translationManager.emptyString
|
||||
informationPopup.icon = StandardIcon.Information
|
||||
informationPopup.onCloseCallback = null
|
||||
informationPopup.open();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.SettingsListItem {
|
||||
buttonText: qsTr("Change password") + translationManager.emptyString
|
||||
description: qsTr("Change the password of your wallet.") + translationManager.emptyString
|
||||
title: qsTr("Change wallet password") + translationManager.emptyString
|
||||
|
||||
onClicked: {
|
||||
passwordDialog.onAcceptedCallback = function() {
|
||||
if(appWindow.walletPassword === passwordDialog.password){
|
||||
passwordDialog.openNewPasswordDialog()
|
||||
} else {
|
||||
informationPopup.title = qsTr("Error") + translationManager.emptyString;
|
||||
informationPopup.text = currentWallet.errorString;
|
||||
informationPopup.text = qsTr("Wrong password") + translationManager.emptyString;
|
||||
informationPopup.open()
|
||||
informationPopup.onCloseCallback = function() {
|
||||
passwordDialog.open()
|
||||
}
|
||||
}
|
||||
}
|
||||
width: 135
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
// divider
|
||||
visible: !appWindow.viewOnly
|
||||
Layout.preferredHeight: 1
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 8
|
||||
Layout.bottomMargin: 8
|
||||
color: MoneroComponents.Style.dividerColor
|
||||
opacity: MoneroComponents.Style.dividerOpacity
|
||||
}
|
||||
|
||||
GridLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: childrenRect.height
|
||||
columnSpacing: 0
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
spacing: 0
|
||||
|
||||
MoneroComponents.TextPlain {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 20
|
||||
Layout.topMargin: 8
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
opacity: MoneroComponents.Style.blackTheme ? 1.0 : 0.8
|
||||
font.bold: true
|
||||
font.family: MoneroComponents.Style.fontRegular.name
|
||||
font.pixelSize: 16
|
||||
text: qsTr("Show seed & keys") + translationManager.emptyString
|
||||
}
|
||||
|
||||
MoneroComponents.TextPlainArea {
|
||||
color: MoneroComponents.Style.dimmedFontColor
|
||||
colorBlackTheme: MoneroComponents.Style._b_dimmedFontColor
|
||||
colorWhiteTheme: MoneroComponents.Style._w_dimmedFontColor
|
||||
width: parent.width
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: TextInput.AlignLeft
|
||||
text: qsTr("Store this information safely to recover your wallet in the future.") + translationManager.emptyString
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.StandardButton {
|
||||
small: true
|
||||
text: qsTr("Show seed") + translationManager.emptyString
|
||||
onClicked: {
|
||||
Utils.showSeedPage();
|
||||
}
|
||||
width: 135
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
// divider
|
||||
Layout.preferredHeight: 1
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 8
|
||||
Layout.bottomMargin: 8
|
||||
color: MoneroComponents.Style.dividerColor
|
||||
opacity: MoneroComponents.Style.dividerOpacity
|
||||
}
|
||||
|
||||
GridLayout {
|
||||
visible: appWindow.walletMode >= 2
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: childrenRect.height
|
||||
columnSpacing: 0
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
spacing: 0
|
||||
|
||||
MoneroComponents.TextPlain {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 20
|
||||
Layout.topMargin: 8
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
opacity: MoneroComponents.Style.blackTheme ? 1.0 : 0.8
|
||||
font.bold: true
|
||||
font.family: MoneroComponents.Style.fontRegular.name
|
||||
font.pixelSize: 16
|
||||
text: qsTr("Rescan wallet balance") + translationManager.emptyString
|
||||
}
|
||||
|
||||
MoneroComponents.TextPlainArea {
|
||||
color: MoneroComponents.Style.dimmedFontColor
|
||||
colorBlackTheme: MoneroComponents.Style._b_dimmedFontColor
|
||||
colorWhiteTheme: MoneroComponents.Style._w_dimmedFontColor
|
||||
width: parent.width
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: TextInput.AlignLeft
|
||||
text: qsTr("Use this feature if you think the shown balance is not accurate.") + translationManager.emptyString
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.StandardButton {
|
||||
small: true
|
||||
text: qsTr("Rescan") + translationManager.emptyString
|
||||
onClicked: {
|
||||
if (!currentWallet.rescanSpent()) {
|
||||
console.error("Error: ", currentWallet.errorString);
|
||||
informationPopup.title = qsTr("Error") + translationManager.emptyString;
|
||||
informationPopup.text = qsTr("Error: ") + currentWallet.errorString
|
||||
informationPopup.icon = StandardIcon.Critical
|
||||
informationPopup.onCloseCallback = null
|
||||
informationPopup.open();
|
||||
} else {
|
||||
informationPopup.title = qsTr("Information") + translationManager.emptyString
|
||||
informationPopup.text = qsTr("Successfully rescanned spent outputs.") + translationManager.emptyString
|
||||
informationPopup.icon = StandardIcon.Information
|
||||
informationPopup.onCloseCallback = null
|
||||
informationPopup.open();
|
||||
}
|
||||
}
|
||||
width: 135
|
||||
}
|
||||
}
|
||||
Rectangle {
|
||||
// divider
|
||||
visible: appWindow.walletMode >= 2
|
||||
Layout.preferredHeight: 1
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 8
|
||||
Layout.bottomMargin: 8
|
||||
color: MoneroComponents.Style.dividerColor
|
||||
opacity: MoneroComponents.Style.dividerOpacity
|
||||
}
|
||||
|
||||
GridLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: childrenRect.height
|
||||
columnSpacing: 0
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
spacing: 0
|
||||
|
||||
MoneroComponents.TextPlain {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 20
|
||||
Layout.topMargin: 8
|
||||
color: MoneroComponents.Style.defaultFontColor
|
||||
opacity: MoneroComponents.Style.blackTheme ? 1.0 : 0.8
|
||||
font.bold: true
|
||||
font.family: MoneroComponents.Style.fontRegular.name
|
||||
font.pixelSize: 16
|
||||
text: qsTr("Change wallet password") + translationManager.emptyString
|
||||
}
|
||||
|
||||
MoneroComponents.TextPlainArea {
|
||||
color: MoneroComponents.Style.dimmedFontColor
|
||||
colorBlackTheme: MoneroComponents.Style._b_dimmedFontColor
|
||||
colorWhiteTheme: MoneroComponents.Style._w_dimmedFontColor
|
||||
width: parent.width
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: TextInput.AlignLeft
|
||||
text: qsTr("Change the password of your wallet.") + translationManager.emptyString
|
||||
}
|
||||
}
|
||||
|
||||
MoneroComponents.StandardButton {
|
||||
small: true
|
||||
text: qsTr("Change password") + translationManager.emptyString
|
||||
onClicked: {
|
||||
passwordDialog.onAcceptedCallback = function() {
|
||||
if(appWindow.walletPassword === passwordDialog.password){
|
||||
newPasswordDialog.open()
|
||||
} else {
|
||||
informationPopup.title = qsTr("Error") + translationManager.emptyString;
|
||||
informationPopup.text = qsTr("Wrong password") + translationManager.emptyString;
|
||||
informationPopup.open()
|
||||
informationPopup.onCloseCallback = function() {
|
||||
passwordDialog.open()
|
||||
}
|
||||
}
|
||||
}
|
||||
passwordDialog.onRejectedCallback = null;
|
||||
passwordDialog.open()
|
||||
}
|
||||
width: 135
|
||||
passwordDialog.onRejectedCallback = null;
|
||||
passwordDialog.open()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
21
qml.qrc
@@ -12,6 +12,7 @@
|
||||
<file>images/plus-white.png</file>
|
||||
<file>images/plus-white@2x.png</file>
|
||||
<file>components/Label.qml</file>
|
||||
<file>components/SettingsListItem.qml</file>
|
||||
<file>images/whatIsIcon.png</file>
|
||||
<file>images/whatIsIcon@2x.png</file>
|
||||
<file>images/lockIcon.png</file>
|
||||
@@ -21,6 +22,8 @@
|
||||
<file>pages/History.qml</file>
|
||||
<file>pages/AddressBook.qml</file>
|
||||
<file>pages/Mining.qml</file>
|
||||
<file>components/ContextMenu.qml</file>
|
||||
<file>components/ContextMenuItem.qml</file>
|
||||
<file>components/NetworkStatusItem.qml</file>
|
||||
<file>components/Input.qml</file>
|
||||
<file>components/StandardButton.qml</file>
|
||||
@@ -96,9 +99,7 @@
|
||||
<file>pages/SharedRingDB.qml</file>
|
||||
<file>components/effects/ImageMask.qml</file>
|
||||
<file>components/IconButton.qml</file>
|
||||
<file>components/PassphraseDialog.qml</file>
|
||||
<file>components/PasswordDialog.qml</file>
|
||||
<file>components/NewPasswordDialog.qml</file>
|
||||
<file>components/InputDialog.qml</file>
|
||||
<file>components/ProcessingSplash.qml</file>
|
||||
<file>components/ProgressBar.qml</file>
|
||||
@@ -109,13 +110,14 @@
|
||||
<file>components/DaemonConsole.qml</file>
|
||||
<file>components/QRCodeScanner.qml</file>
|
||||
<file>components/Notifier.qml</file>
|
||||
<file>components/MobileHeader.qml</file>
|
||||
<file>components/TextBlock.qml</file>
|
||||
<file>components/RemoteNodeEdit.qml</file>
|
||||
<file>pages/Keys.qml</file>
|
||||
<file>images/appicon.ico</file>
|
||||
<file>images/card-background.png</file>
|
||||
<file>images/card-background@2x.png</file>
|
||||
<file>images/card-background-black.png</file>
|
||||
<file>images/card-background-black@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/question.png</file>
|
||||
<file>images/question@2x.png</file>
|
||||
@@ -169,8 +171,6 @@
|
||||
<file>pages/settings/SettingsLayout.qml</file>
|
||||
<file>pages/settings/SettingsInfo.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>images/miningxmr.png</file>
|
||||
<file>images/miningxmr@2x.png</file>
|
||||
@@ -182,7 +182,9 @@
|
||||
<file>images/merchant/arrow_right.png</file>
|
||||
<file>images/merchant/bg.png</file>
|
||||
<file>images/merchant/input_box.png</file>
|
||||
<file>fonts/FontAwesome/fontawesome-webfont.ttf</file>
|
||||
<file>fonts/FontAwesome/fa-brands-400.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/Object.qml</file>
|
||||
<file>fonts/FontAwesome/qmldir</file>
|
||||
@@ -238,7 +240,6 @@
|
||||
<file>images/middlePanelShadow.png</file>
|
||||
<file>images/themes/white/titlebarLogo@2x.png</file>
|
||||
<file>images/themes/white/titlebarLogo.png</file>
|
||||
<file>images/sidebar.svg</file>
|
||||
<file>images/fullscreen.svg</file>
|
||||
<file>images/close.svg</file>
|
||||
<file>images/minimize.svg</file>
|
||||
@@ -246,12 +247,12 @@
|
||||
<file>images/themes/white/fullscreen.svg</file>
|
||||
<file>images/themes/white/minimize.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/GradientBackground.qml</file>
|
||||
<file>images/check-white.svg</file>
|
||||
<file>images/copy.svg</file>
|
||||
<file>images/edit.svg</file>
|
||||
<file>images/arrow-right-in-circle-outline-medium-white.svg</file>
|
||||
<file>images/tails-grey.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
#include <QMap>
|
||||
|
||||
namespace {
|
||||
static const int DAEMON_START_TIMEOUT_SECONDS = 30;
|
||||
static const int DAEMON_START_TIMEOUT_SECONDS = 60;
|
||||
}
|
||||
|
||||
DaemonManager * DaemonManager::m_instance = nullptr;
|
||||
@@ -61,7 +61,7 @@ DaemonManager *DaemonManager::instance(const QStringList *args)
|
||||
return m_instance;
|
||||
}
|
||||
|
||||
bool DaemonManager::start(const QString &flags, NetworkType::Type nettype, const QString &dataDir, const QString &bootstrapNodeAddress)
|
||||
bool DaemonManager::start(const QString &flags, NetworkType::Type nettype, const QString &dataDir, const QString &bootstrapNodeAddress, bool noSync /* = false*/)
|
||||
{
|
||||
// prepare command line arguments and pass to monerod
|
||||
QStringList arguments;
|
||||
@@ -99,6 +99,10 @@ bool DaemonManager::start(const QString &flags, NetworkType::Type nettype, const
|
||||
arguments << "--bootstrap-daemon-address" << bootstrapNodeAddress;
|
||||
}
|
||||
|
||||
if (noSync) {
|
||||
arguments << "--no-sync";
|
||||
}
|
||||
|
||||
arguments << "--check-updates" << "disabled";
|
||||
|
||||
// --max-concurrency based on threads available. max: 6
|
||||
@@ -131,11 +135,13 @@ bool DaemonManager::start(const QString &flags, NetworkType::Type nettype, const
|
||||
}
|
||||
|
||||
// Start start watcher
|
||||
m_scheduler.run([this, nettype] {
|
||||
if (startWatcher(nettype))
|
||||
m_scheduler.run([this, nettype, noSync] {
|
||||
if (startWatcher(nettype)) {
|
||||
emit daemonStarted();
|
||||
else
|
||||
m_noSync = noSync;
|
||||
} else {
|
||||
emit daemonStartFailure();
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
@@ -144,7 +150,7 @@ bool DaemonManager::start(const QString &flags, NetworkType::Type nettype, const
|
||||
bool DaemonManager::stop(NetworkType::Type nettype)
|
||||
{
|
||||
QString message;
|
||||
sendCommand("exit", nettype, message);
|
||||
sendCommand({"exit"}, nettype, message);
|
||||
qDebug() << message;
|
||||
|
||||
// Start stop watcher - Will kill if not shutting down
|
||||
@@ -234,26 +240,27 @@ void DaemonManager::printError()
|
||||
bool DaemonManager::running(NetworkType::Type nettype) const
|
||||
{
|
||||
QString status;
|
||||
sendCommand("status", nettype, status);
|
||||
sendCommand({"sync_info"}, nettype, status);
|
||||
qDebug() << status;
|
||||
// `./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
|
||||
{
|
||||
QString message;
|
||||
return sendCommand(cmd, nettype, message);
|
||||
return status.contains("Height:");
|
||||
}
|
||||
|
||||
bool DaemonManager::sendCommand(const QString &cmd, NetworkType::Type nettype, QString &message) const
|
||||
bool DaemonManager::noSync() const noexcept
|
||||
{
|
||||
return m_noSync;
|
||||
}
|
||||
|
||||
void DaemonManager::runningAsync(NetworkType::Type nettype, const QJSValue& callback) 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;
|
||||
QStringList external_cmd;
|
||||
external_cmd << cmd;
|
||||
QStringList external_cmd(cmd);
|
||||
|
||||
// Add network type flag if needed
|
||||
if (nettype == NetworkType::TESTNET)
|
||||
@@ -272,6 +279,14 @@ bool DaemonManager::sendCommand(const QString &cmd, NetworkType::Type nettype, Q
|
||||
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()
|
||||
{
|
||||
qDebug("DaemonManager: exit()");
|
||||
|
||||
@@ -44,19 +44,21 @@ public:
|
||||
|
||||
static DaemonManager * instance(const QStringList *args);
|
||||
|
||||
Q_INVOKABLE bool start(const QString &flags, NetworkType::Type nettype, const QString &dataDir = "", const QString &bootstrapNodeAddress = "");
|
||||
Q_INVOKABLE bool start(const QString &flags, NetworkType::Type nettype, const QString &dataDir = "", const QString &bootstrapNodeAddress = "", bool noSync = false);
|
||||
Q_INVOKABLE bool stop(NetworkType::Type nettype);
|
||||
|
||||
Q_INVOKABLE bool noSync() const noexcept;
|
||||
// return true if daemon process is started
|
||||
Q_INVOKABLE bool running(NetworkType::Type nettype) const;
|
||||
Q_INVOKABLE void runningAsync(NetworkType::Type nettype, const QJSValue& callback) const;
|
||||
// Send daemon command from qml and prints output in console window.
|
||||
Q_INVOKABLE bool sendCommand(const QString &cmd, NetworkType::Type nettype) const;
|
||||
Q_INVOKABLE void sendCommandAsync(const QStringList &cmd, NetworkType::Type nettype, const QJSValue& callback) const;
|
||||
Q_INVOKABLE void exit();
|
||||
Q_INVOKABLE QVariantMap validateDataDir(const QString &dataDir) const;
|
||||
|
||||
private:
|
||||
|
||||
bool sendCommand(const QString &cmd, NetworkType::Type nettype, QString &message) const;
|
||||
bool running(NetworkType::Type nettype) const;
|
||||
bool sendCommand(const QStringList &cmd, NetworkType::Type nettype, QString &message) const;
|
||||
bool startWatcher(NetworkType::Type nettype) const;
|
||||
bool stopWatcher(NetworkType::Type nettype) const;
|
||||
signals:
|
||||
@@ -81,8 +83,9 @@ private:
|
||||
QString m_monerod;
|
||||
bool m_has_daemon = true;
|
||||
bool m_app_exit = false;
|
||||
bool m_noSync = false;
|
||||
|
||||
FutureScheduler m_scheduler;
|
||||
mutable FutureScheduler m_scheduler;
|
||||
};
|
||||
|
||||
#endif // DAEMONMANAGER_H
|
||||
|
||||
@@ -40,7 +40,7 @@ QString UnsignedTransaction::errorString() const
|
||||
return QString::fromStdString(m_pimpl->errorString());
|
||||
}
|
||||
|
||||
quint64 UnsignedTransaction::amount(int index) const
|
||||
quint64 UnsignedTransaction::amount(size_t index) const
|
||||
{
|
||||
std::vector<uint64_t> arr = m_pimpl->amount();
|
||||
if(index > arr.size() - 1)
|
||||
@@ -48,7 +48,7 @@ quint64 UnsignedTransaction::amount(int index) const
|
||||
return arr[index];
|
||||
}
|
||||
|
||||
quint64 UnsignedTransaction::fee(int index) const
|
||||
quint64 UnsignedTransaction::fee(size_t index) const
|
||||
{
|
||||
std::vector<uint64_t> arr = m_pimpl->fee();
|
||||
if(index > arr.size() - 1)
|
||||
@@ -56,7 +56,7 @@ quint64 UnsignedTransaction::fee(int index) const
|
||||
return arr[index];
|
||||
}
|
||||
|
||||
quint64 UnsignedTransaction::mixin(int index) const
|
||||
quint64 UnsignedTransaction::mixin(size_t index) const
|
||||
{
|
||||
std::vector<uint64_t> arr = m_pimpl->mixin();
|
||||
if(index > arr.size() - 1)
|
||||
|
||||
@@ -56,9 +56,9 @@ public:
|
||||
|
||||
Status status() const;
|
||||
QString errorString() const;
|
||||
Q_INVOKABLE quint64 amount(int index) const;
|
||||
Q_INVOKABLE quint64 fee(int index) const;
|
||||
Q_INVOKABLE quint64 mixin(int index) const;
|
||||
Q_INVOKABLE quint64 amount(size_t index) const;
|
||||
Q_INVOKABLE quint64 fee(size_t index) const;
|
||||
Q_INVOKABLE quint64 mixin(size_t index) const;
|
||||
QStringList recipientAddress() const;
|
||||
QStringList paymentId() const;
|
||||
quint64 txCount() const;
|
||||
|
||||
@@ -206,7 +206,7 @@ bool Wallet::store(const QString &path)
|
||||
return m_walletImpl->store(path.toStdString());
|
||||
}
|
||||
|
||||
bool Wallet::init(const QString &daemonAddress, quint64 upperTransactionLimit, bool isRecovering, bool isRecoveringFromDevice, quint64 restoreHeight)
|
||||
bool Wallet::init(const QString &daemonAddress, bool trustedDaemon, quint64 upperTransactionLimit, bool isRecovering, bool isRecoveringFromDevice, quint64 restoreHeight)
|
||||
{
|
||||
qDebug() << "init non async";
|
||||
if (isRecovering){
|
||||
@@ -221,6 +221,7 @@ bool Wallet::init(const QString &daemonAddress, quint64 upperTransactionLimit, b
|
||||
m_walletImpl->setRefreshFromBlockHeight(restoreHeight);
|
||||
}
|
||||
m_walletImpl->init(daemonAddress.toStdString(), upperTransactionLimit, m_daemonUsername.toStdString(), m_daemonPassword.toStdString());
|
||||
setTrustedDaemon(trustedDaemon);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -231,7 +232,7 @@ void Wallet::setDaemonLogin(const QString &daemonUsername, const QString &daemon
|
||||
m_daemonPassword = daemonPassword;
|
||||
}
|
||||
|
||||
void Wallet::initAsync(const QString &daemonAddress, quint64 upperTransactionLimit, bool isRecovering, bool isRecoveringFromDevice, quint64 restoreHeight)
|
||||
void Wallet::initAsync(const QString &daemonAddress, bool trustedDaemon, quint64 upperTransactionLimit, bool isRecovering, bool isRecoveringFromDevice, quint64 restoreHeight)
|
||||
{
|
||||
qDebug() << "initAsync: " + daemonAddress;
|
||||
// Change status to disconnected if connected
|
||||
@@ -240,19 +241,28 @@ void Wallet::initAsync(const QString &daemonAddress, quint64 upperTransactionLim
|
||||
emit connectionStatusChanged(m_connectionStatus);
|
||||
}
|
||||
|
||||
m_scheduler.run([this, daemonAddress, upperTransactionLimit, isRecovering, isRecoveringFromDevice, restoreHeight] {
|
||||
bool success = init(daemonAddress, upperTransactionLimit, isRecovering, isRecoveringFromDevice, restoreHeight);
|
||||
m_scheduler.run([this, daemonAddress, trustedDaemon, upperTransactionLimit, isRecovering, isRecoveringFromDevice, restoreHeight] {
|
||||
bool success = init(daemonAddress, trustedDaemon, upperTransactionLimit, isRecovering, isRecoveringFromDevice, restoreHeight);
|
||||
if (success)
|
||||
{
|
||||
emit walletCreationHeightChanged();
|
||||
qDebug() << "init async finished - starting refresh";
|
||||
connected(true);
|
||||
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
|
||||
bool Wallet::createViewOnly(const QString &path, const QString &password) const
|
||||
{
|
||||
@@ -335,6 +345,13 @@ void Wallet::setSubaddressLabel(quint32 accountIndex, quint32 addressIndex, cons
|
||||
{
|
||||
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()
|
||||
{
|
||||
@@ -524,7 +541,8 @@ bool Wallet::submitTxFile(const QString &fileName) const
|
||||
void Wallet::commitTransactionAsync(PendingTransaction *t)
|
||||
{
|
||||
m_scheduler.run([this, t] {
|
||||
emit transactionCommitted(t->commit(), t, t->txid());
|
||||
auto txIdList = t->txid(); // retrieve before commit
|
||||
emit transactionCommitted(t->commit(), t, txIdList);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -622,6 +640,15 @@ void Wallet::setPaymentId(const QString &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 ¬e)
|
||||
{
|
||||
return m_walletImpl->setUserNote(txid.toStdString(), note.toStdString());
|
||||
@@ -936,16 +963,16 @@ Wallet::Wallet(Monero::Wallet *w, QObject *parent)
|
||||
, m_historyModel(nullptr)
|
||||
, m_addressBook(nullptr)
|
||||
, m_addressBookModel(nullptr)
|
||||
, m_subaddress(nullptr)
|
||||
, m_subaddressModel(nullptr)
|
||||
, m_subaddressAccount(nullptr)
|
||||
, m_subaddressAccountModel(nullptr)
|
||||
, m_daemonBlockChainHeight(0)
|
||||
, m_daemonBlockChainHeightTtl(DAEMON_BLOCKCHAIN_HEIGHT_CACHE_TTL_SECONDS)
|
||||
, m_daemonBlockChainTargetHeight(0)
|
||||
, m_daemonBlockChainTargetHeightTtl(DAEMON_BLOCKCHAIN_TARGET_HEIGHT_CACHE_TTL_SECONDS)
|
||||
, m_connectionStatusTtl(WALLET_CONNECTION_STATUS_CACHE_TTL_SECONDS)
|
||||
, m_currentSubaddressAccount(0)
|
||||
, m_subaddress(nullptr)
|
||||
, m_subaddressModel(nullptr)
|
||||
, m_subaddressAccount(nullptr)
|
||||
, m_subaddressAccountModel(nullptr)
|
||||
, m_scheduler(this)
|
||||
{
|
||||
m_history = new TransactionHistory(m_walletImpl->history(), this);
|
||||
|
||||
@@ -144,11 +144,8 @@ public:
|
||||
//! empty path stores in current location
|
||||
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
|
||||
Q_INVOKABLE void initAsync(const QString &daemonAddress, quint64 upperTransactionLimit = 0, bool isRecovering = false, bool isRecoveringFromDevice = false, quint64 restoreHeight = 0);
|
||||
Q_INVOKABLE void initAsync(const QString &daemonAddress, bool trustedDaemon = false, quint64 upperTransactionLimit = 0, bool isRecovering = false, bool isRecoveringFromDevice = false, quint64 restoreHeight = 0);
|
||||
|
||||
// Set daemon rpc user/pass
|
||||
Q_INVOKABLE void setDaemonLogin(const QString &daemonUsername = "", const QString &daemonPassword = "");
|
||||
@@ -179,6 +176,11 @@ public:
|
||||
Q_INVOKABLE void addSubaddress(const QString& label);
|
||||
Q_INVOKABLE QString getSubaddressLabel(quint32 accountIndex, quint32 addressIndex) const;
|
||||
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
|
||||
Q_INVOKABLE bool viewOnly() const;
|
||||
@@ -288,6 +290,10 @@ public:
|
||||
|
||||
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 ¬e);
|
||||
Q_INVOKABLE QString getUserNote(const QString &txid) const;
|
||||
Q_INVOKABLE QString getTxKey(const QString &txid) const;
|
||||
@@ -351,8 +357,9 @@ signals:
|
||||
void walletCreationHeightChanged();
|
||||
void deviceButtonRequest(quint64 buttonCode);
|
||||
void deviceButtonPressed();
|
||||
void transactionCommitted(bool status, PendingTransaction *t, QStringList txid);
|
||||
void transactionCommitted(bool status, PendingTransaction *t, const QStringList& txid);
|
||||
void heightRefreshed(quint64 walletHeight, quint64 daemonHeight, quint64 targetHeight) const;
|
||||
void deviceShowAddressShowed();
|
||||
|
||||
// emitted when transaction is created async
|
||||
void transactionCreated(PendingTransaction * transaction, QString address, QString paymentId, quint32 mixinCount);
|
||||
@@ -374,6 +381,9 @@ private:
|
||||
//! returns daemon's blockchain target height
|
||||
quint64 daemonBlockChainTargetHeight() const;
|
||||
|
||||
//! initializes wallet
|
||||
bool init(const QString &daemonAddress, bool trustedDaemon, quint64 upperTransactionLimit, bool isRecovering, bool isRecoveringFromDevice, quint64 restoreHeight);
|
||||
|
||||
private:
|
||||
friend class WalletManager;
|
||||
friend class WalletListenerImpl;
|
||||
@@ -385,6 +395,8 @@ private:
|
||||
mutable TransactionHistoryModel * m_historyModel;
|
||||
mutable TransactionHistorySortFilterModel * m_historySortFilterModel;
|
||||
QString m_paymentId;
|
||||
AddressBook * m_addressBook;
|
||||
mutable AddressBookModel * m_addressBookModel;
|
||||
mutable QTime m_daemonBlockChainHeightTime;
|
||||
mutable quint64 m_daemonBlockChainHeight;
|
||||
int m_daemonBlockChainHeightTtl;
|
||||
@@ -396,8 +408,6 @@ private:
|
||||
mutable QTime m_connectionStatusTime;
|
||||
mutable bool m_initialized;
|
||||
uint32_t m_currentSubaddressAccount;
|
||||
AddressBook * m_addressBook;
|
||||
mutable AddressBookModel * m_addressBookModel;
|
||||
Subaddress * m_subaddress;
|
||||
mutable SubaddressModel * m_subaddressModel;
|
||||
SubaddressAccount * m_subaddressAccount;
|
||||
|
||||
@@ -66,7 +66,7 @@ public:
|
||||
}
|
||||
|
||||
auto tmpPass = m_mgr->m_passphrase.toStdString();
|
||||
m_mgr->m_passphrase = QString::null;
|
||||
m_mgr->m_passphrase = QString();
|
||||
|
||||
return Monero::optional<std::string>(tmpPass);
|
||||
}
|
||||
@@ -228,11 +228,11 @@ QString WalletManager::closeWallet()
|
||||
return result;
|
||||
}
|
||||
|
||||
void WalletManager::closeWalletAsync()
|
||||
void WalletManager::closeWalletAsync(const QJSValue& callback)
|
||||
{
|
||||
m_scheduler.run([this] {
|
||||
emit walletClosed(closeWallet());
|
||||
});
|
||||
return QJSValueList({closeWallet()});
|
||||
}, callback);
|
||||
}
|
||||
|
||||
bool WalletManager::walletExists(const QString &path) const
|
||||
@@ -376,7 +376,7 @@ bool WalletManager::localDaemonSynced() const
|
||||
|
||||
bool WalletManager::isDaemonLocal(const QString &daemon_address) const
|
||||
{
|
||||
return Monero::Utils::isAddressLocal(daemon_address.toStdString());
|
||||
return daemon_address.isEmpty() ? false : Monero::Utils::isAddressLocal(daemon_address.toStdString());
|
||||
}
|
||||
|
||||
QString WalletManager::resolveOpenAlias(const QString &address) const
|
||||
|
||||
@@ -117,7 +117,7 @@ public:
|
||||
/*!
|
||||
* \brief closeWalletAsync - asynchronous version of "closeWallet"
|
||||
*/
|
||||
Q_INVOKABLE void closeWalletAsync();
|
||||
Q_INVOKABLE void closeWalletAsync(const QJSValue& callback);
|
||||
|
||||
//! checks is given filename is a wallet;
|
||||
Q_INVOKABLE bool walletExists(const QString &path) const;
|
||||
@@ -192,7 +192,6 @@ signals:
|
||||
void walletPassphraseNeeded();
|
||||
void deviceButtonRequest(quint64 buttonCode);
|
||||
void deviceButtonPressed();
|
||||
void walletClosed(const QString &walletAddress);
|
||||
void checkUpdatesComplete(const QString &result) const;
|
||||
void miningStatus(bool isMining) const;
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ void AddressBookModel::endReset(){
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
int AddressBookModel::rowCount(const QModelIndex &parent) const
|
||||
int AddressBookModel::rowCount(const QModelIndex &) const
|
||||
{
|
||||
return m_addressBook->count();
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ void SubaddressAccountModel::endReset(){
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
int SubaddressAccountModel::rowCount(const QModelIndex &parent) const
|
||||
int SubaddressAccountModel::rowCount(const QModelIndex &) const
|
||||
{
|
||||
return m_subaddressAccount->count();
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ void SubaddressModel::endReset(){
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
int SubaddressModel::rowCount(const QModelIndex &parent) const
|
||||
int SubaddressModel::rowCount(const QModelIndex &) const
|
||||
{
|
||||
return m_subaddress->count();
|
||||
}
|
||||
|
||||
@@ -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) noexcept
|
||||
QPair<bool, QFuture<QJSValueList>> FutureScheduler::run(std::function<QJSValueList() noexcept> function, const QJSValue &callback)
|
||||
{
|
||||
if (!callback.isCallable())
|
||||
{
|
||||
|
||||
@@ -20,9 +20,9 @@ public:
|
||||
~FutureScheduler();
|
||||
|
||||
void shutdownWaitForFinished() noexcept;
|
||||
|
||||
|
||||
QPair<bool, QFuture<void>> run(std::function<void()> function) noexcept;
|
||||
QPair<bool, QFuture<QJSValueList>> run(std::function<QJSValueList() noexcept> function, const QJSValue &callback) noexcept;
|
||||
QPair<bool, QFuture<QJSValueList>> run(std::function<QJSValueList() noexcept> function, const QJSValue &callback);
|
||||
|
||||
private:
|
||||
bool add() noexcept;
|
||||
@@ -38,7 +38,7 @@ private:
|
||||
watcher->moveToThread(schedulerThread);
|
||||
}
|
||||
watcher->setParent(this);
|
||||
|
||||
|
||||
return watcher;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,9 +36,9 @@
|
||||
#include <QMutex>
|
||||
#include <QMutexLocker>
|
||||
#include <QString>
|
||||
#include "src/libwalletqt/WalletManager.h"
|
||||
#include "src/NetworkType.h"
|
||||
#include "src/qt/utils.h"
|
||||
#include "libwalletqt/WalletManager.h"
|
||||
#include "NetworkType.h"
|
||||
#include "qt/utils.h"
|
||||
|
||||
#include "KeysFiles.h"
|
||||
|
||||
|
||||
@@ -30,8 +30,8 @@
|
||||
#define KEYSFILES_H
|
||||
|
||||
#include <qqmlcontext.h>
|
||||
#include "src/libwalletqt/WalletManager.h"
|
||||
#include "src/NetworkType.h"
|
||||
#include "libwalletqt/WalletManager.h"
|
||||
#include "NetworkType.h"
|
||||
#include <QtCore>
|
||||
|
||||
class WalletKeysFiles
|
||||
|
||||
208
src/qt/MoneroSettings.cpp
Normal file
@@ -0,0 +1,208 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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)
|
||||
{
|
||||
}
|
||||