Compare commits

..

2 Commits

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

19
.gitignore vendored
View File

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

View File

@@ -114,12 +114,13 @@ Rectangle {
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: (persistentSettings.customDecorations)? 50 : 0 anchors.topMargin: (persistentSettings.customDecorations)? 50 : 0
Item { RowLayout {
Item { Item {
anchors.left: parent.left anchors.left: parent.left
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: 20 anchors.topMargin: 20
anchors.leftMargin: 20 anchors.leftMargin: 20
anchors.verticalCenter: parent.verticalCenter
height: 490 height: 490
width: 260 width: 260
@@ -229,6 +230,7 @@ Rectangle {
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: 20 anchors.topMargin: 20
anchors.leftMargin: 20 anchors.leftMargin: 20
anchors.verticalCenter: parent.verticalCenter
height: 490 height: 490
width: 50 width: 50

View File

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

View File

@@ -209,13 +209,13 @@ Rectangle {
clip: true clip: true
ScrollBar.vertical: ScrollBar { ScrollBar.vertical: ScrollBar {
parent: root parent: mainFlickable.parent
anchors.left: parent.right anchors.left: parent.right
anchors.leftMargin: -14 // 10 margin + 4 scrollbar width anchors.leftMargin: 3
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: persistentSettings.customDecorations ? 60 : 10 anchors.topMargin: 4
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.bottomMargin: persistentSettings.customDecorations ? 15 : 10 anchors.bottomMargin: persistentSettings.customDecorations ? 4 : 0
} }
onFlickingChanged: { onFlickingChanged: {

View File

@@ -165,8 +165,9 @@ The executable can be found in the build/release/bin folder.
5. Add the Qt bin directory to your path 5. Add the Qt bin directory to your path
- Example for Qt: `export PATH=$PATH:$HOME/Qt/5.9.7/clang_64/bin` Example: `export PATH=$PATH:$HOME/Qt/5.9.7/clang_64/bin`
- Example for Homebrew: `export PATH=$PATH:/usr/local/opt/qt/bin`
This is the directory where Qt 5.x is installed on **your** system
6. Grab an up-to-date copy of the monero-gui repository 6. Grab an up-to-date copy of the monero-gui repository

View File

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

View File

@@ -88,7 +88,6 @@ Rectangle {
} }
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
visible: appWindow.walletMode >= 2
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
if(!appWindow.isMining) { if(!appWindow.isMining) {
@@ -134,7 +133,6 @@ Rectangle {
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
visible: appWindow.walletMode >= 2
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
if(!appWindow.isMining) { if(!appWindow.isMining) {

View File

@@ -0,0 +1,287 @@
// Copyright (c) 2014-2019, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import QtQuick 2.9
import QtQuick.Controls 2.0
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.1
import QtQuick.Controls.Styles 1.4
import QtQuick.Window 2.0
import FontAwesome 1.0
import "../components" as MoneroComponents
Item {
id: root
visible: false
z: parent.z + 2
property bool isHidden: true
property alias password: passwordInput1.text
// same signals as Dialog has
signal accepted()
signal rejected()
signal closeCallback()
function open() {
isHidden = true
passwordInput1.echoMode = TextInput.Password;
passwordInput2.echoMode = TextInput.Password;
inactiveOverlay.visible = true
leftPanel.enabled = false
middlePanel.enabled = false
titleBar.state = "essentials"
root.visible = true;
passwordInput1.text = "";
passwordInput2.text = "";
passwordInput1.focus = true
}
function close() {
inactiveOverlay.visible = false
leftPanel.enabled = true
middlePanel.enabled = true
titleBar.state = "default"
root.visible = false;
closeCallback();
}
function toggleIsHidden() {
passwordInput1.echoMode = isHidden ? TextInput.Normal : TextInput.Password;
passwordInput2.echoMode = isHidden ? TextInput.Normal : TextInput.Password;
isHidden = !isHidden;
}
// TODO: implement without hardcoding sizes
width: 480
height: 360
ColumnLayout {
z: inactiveOverlay.z + 1
id: mainLayout
spacing: 10
anchors { fill: parent; margins: 35 }
ColumnLayout {
id: column
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
Layout.maximumWidth: 400
Label {
text: qsTr("Please enter new password") + translationManager.emptyString
Layout.fillWidth: true
font.pixelSize: 16
font.family: MoneroComponents.Style.fontLight.name
color: MoneroComponents.Style.defaultFontColor
}
TextField {
id : passwordInput1
Layout.topMargin: 6
Layout.fillWidth: true
horizontalAlignment: TextInput.AlignLeft
verticalAlignment: TextInput.AlignVCenter
font.family: MoneroComponents.Style.fontLight.name
font.pixelSize: 24
echoMode: TextInput.Password
bottomPadding: 10
leftPadding: 10
topPadding: 10
color: MoneroComponents.Style.defaultFontColor
selectionColor: MoneroComponents.Style.textSelectionColor
selectedTextColor: MoneroComponents.Style.textSelectedColor
KeyNavigation.tab: passwordInput2
background: Rectangle {
radius: 2
border.color: MoneroComponents.Style.inputBorderColorInActive
border.width: 1
color: MoneroComponents.Style.blackTheme ? "black" : "#A9FFFFFF"
MoneroComponents.Label {
fontSize: 20
text: isHidden ? FontAwesome.eye : FontAwesome.eyeSlash
opacity: 0.7
fontFamily: FontAwesome.fontFamily
anchors.right: parent.right
anchors.rightMargin: 15
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: 1
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
onClicked: {
toggleIsHidden()
}
onEntered: {
parent.opacity = 0.9
parent.fontSize = 24
}
onExited: {
parent.opacity = 0.7
parent.fontSize = 20
}
}
}
}
Keys.onEscapePressed: {
root.close()
root.rejected()
}
}
// padding
Rectangle {
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
height: 10
opacity: 0
color: "black"
}
Label {
text: qsTr("Please confirm new password") + translationManager.emptyString
Layout.fillWidth: true
font.pixelSize: 16
font.family: MoneroComponents.Style.fontLight.name
color: MoneroComponents.Style.defaultFontColor
}
TextField {
id : passwordInput2
Layout.topMargin: 6
Layout.fillWidth: true
horizontalAlignment: TextInput.AlignLeft
verticalAlignment: TextInput.AlignVCenter
font.family: MoneroComponents.Style.fontLight.name
font.pixelSize: 24
echoMode: TextInput.Password
KeyNavigation.tab: okButton
bottomPadding: 10
leftPadding: 10
topPadding: 10
color: MoneroComponents.Style.defaultFontColor
selectionColor: MoneroComponents.Style.textSelectionColor
selectedTextColor: MoneroComponents.Style.textSelectedColor
background: Rectangle {
radius: 2
border.color: MoneroComponents.Style.inputBorderColorInActive
border.width: 1
color: MoneroComponents.Style.blackTheme ? "black" : "#A9FFFFFF"
MoneroComponents.Label {
fontSize: 20
text: isHidden ? FontAwesome.eye : FontAwesome.eyeSlash
opacity: 0.7
fontFamily: FontAwesome.fontFamily
anchors.right: parent.right
anchors.rightMargin: 15
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: 1
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
onClicked: {
toggleIsHidden()
}
onEntered: {
parent.opacity = 0.9
parent.fontSize = 24
}
onExited: {
parent.opacity = 0.7
parent.fontSize = 20
}
}
}
}
Keys.onReturnPressed: {
if (passwordInput1.text === passwordInput2.text) {
root.close()
root.accepted()
}
}
Keys.onEscapePressed: {
root.close()
root.rejected()
}
}
// padding
Rectangle {
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
height: 10
opacity: 0
color: "black"
}
// Ok/Cancel buttons
RowLayout {
id: buttons
spacing: 16
Layout.topMargin: 16
Layout.alignment: Qt.AlignRight
MoneroComponents.StandardButton {
id: cancelButton
text: qsTr("Cancel") + translationManager.emptyString
KeyNavigation.tab: passwordInput1
onClicked: {
root.close()
root.rejected()
}
}
MoneroComponents.StandardButton {
id: okButton
text: qsTr("Continue") + translationManager.emptyString
KeyNavigation.tab: cancelButton
enabled: passwordInput1.text === passwordInput2.text
onClicked: {
root.close()
root.accepted()
}
}
}
}
}
}

View File

@@ -0,0 +1,321 @@
// Copyright (c) 2014-2019, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.1
import QtQuick.Controls.Styles 1.4
import QtQuick.Window 2.0
import FontAwesome 1.0
import "../components" as MoneroComponents
Item {
id: root
visible: false
z: parent.z + 2
property bool isHidden: true
property alias passphrase: passphaseInput1.text
property string walletName
property string errorText
// same signals as Dialog has
signal accepted()
signal rejected()
signal closeCallback()
function open(walletName, errorText) {
isHidden = true
passphaseInput1.echoMode = TextInput.Password;
passphaseInput2.echoMode = TextInput.Password;
inactiveOverlay.visible = true
root.walletName = walletName ? walletName : ""
root.errorText = errorText ? errorText : "";
leftPanel.enabled = false
middlePanel.enabled = false
titleBar.state = "essentials"
root.visible = true;
passphaseInput1.text = "";
passphaseInput2.text = "";
passphaseInput1.focus = true
}
function close() {
inactiveOverlay.visible = false
leftPanel.enabled = true
middlePanel.enabled = true
titleBar.state = "default"
root.visible = false;
closeCallback();
}
function toggleIsHidden() {
passphaseInput1.echoMode = isHidden ? TextInput.Normal : TextInput.Password;
passphaseInput2.echoMode = isHidden ? TextInput.Normal : TextInput.Password;
isHidden = !isHidden;
}
function showError(errorText) {
open(root.walletName, errorText);
}
// TODO: implement without hardcoding sizes
width: 480
height: 360
ColumnLayout {
z: inactiveOverlay.z + 1
id: mainLayout
spacing: 10
anchors { fill: parent; margins: 35 }
ColumnLayout {
id: column
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
Layout.maximumWidth: 400
Label {
text: (root.walletName.length > 0 ? qsTr("Please enter wallet device passphrase for: ") + root.walletName : qsTr("Please enter wallet device passphrase")) + translationManager.emptyString
Layout.fillWidth: true
font.pixelSize: 16
font.family: MoneroComponents.Style.fontLight.name
color: MoneroComponents.Style.defaultFontColor
}
Label {
text: qsTr("Warning: passphrase entry on host is a security risk as it can be captured by malware. It is advised to prefer device-based passphrase entry.") + translationManager.emptyString
Layout.fillWidth: true
wrapMode: Text.Wrap
font.pixelSize: 14
font.family: MoneroComponents.Style.fontLight.name
color: MoneroComponents.Style.warningColor
}
Label {
text: root.errorText
visible: root.errorText
color: MoneroComponents.Style.errorColor
font.pixelSize: 16
font.family: MoneroComponents.Style.fontLight.name
Layout.fillWidth: true
wrapMode: Text.Wrap
}
TextField {
id : passphaseInput1
Layout.topMargin: 6
Layout.fillWidth: true
horizontalAlignment: TextInput.AlignLeft
verticalAlignment: TextInput.AlignVCenter
font.family: MoneroComponents.Style.fontLight.name
font.pixelSize: 24
echoMode: TextInput.Password
bottomPadding: 10
leftPadding: 10
topPadding: 10
color: MoneroComponents.Style.defaultFontColor
selectionColor: MoneroComponents.Style.textSelectionColor
selectedTextColor: MoneroComponents.Style.textSelectedColor
KeyNavigation.tab: passphaseInput2
background: Rectangle {
radius: 2
border.color: MoneroComponents.Style.inputBorderColorInActive
border.width: 1
color: MoneroComponents.Style.blackTheme ? "black" : "#A9FFFFFF"
MoneroComponents.Label {
fontSize: 20
text: isHidden ? FontAwesome.eye : FontAwesome.eyeSlash
opacity: 0.7
fontFamily: FontAwesome.fontFamily
anchors.right: parent.right
anchors.rightMargin: 15
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: 1
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
onClicked: {
toggleIsHidden()
}
onEntered: {
parent.opacity = 0.9
parent.fontSize = 24
}
onExited: {
parent.opacity = 0.7
parent.fontSize = 20
}
}
}
}
Keys.onEscapePressed: {
root.close()
root.rejected()
}
}
// padding
Rectangle {
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
height: 10
opacity: 0
color: "transparent"
}
Label {
text: qsTr("Please re-enter") + translationManager.emptyString
Layout.fillWidth: true
font.pixelSize: 16
font.family: MoneroComponents.Style.fontLight.name
color: MoneroComponents.Style.defaultFontColor
}
TextField {
id : passphaseInput2
Layout.topMargin: 6
Layout.fillWidth: true
horizontalAlignment: TextInput.AlignLeft
verticalAlignment: TextInput.AlignVCenter
font.family: MoneroComponents.Style.fontLight.name
font.pixelSize: 24
echoMode: TextInput.Password
KeyNavigation.tab: okButton
bottomPadding: 10
leftPadding: 10
topPadding: 10
color: MoneroComponents.Style.defaultFontColor
selectionColor: MoneroComponents.Style.dimmedFontColor
selectedTextColor: MoneroComponents.Style.defaultFontColor
background: Rectangle {
radius: 2
border.color: MoneroComponents.Style.inputBorderColorInActive
border.width: 1
color: MoneroComponents.Style.blackTheme ? "black" : "#A9FFFFFF"
MoneroComponents.Label {
fontSize: 20
text: isHidden ? FontAwesome.eye : FontAwesome.eyeSlash
opacity: 0.7
fontFamily: FontAwesome.fontFamily
anchors.right: parent.right
anchors.rightMargin: 15
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: 1
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
onClicked: {
toggleIsHidden()
}
onEntered: {
parent.opacity = 0.9
parent.fontSize = 24
}
onExited: {
parent.opacity = 0.7
parent.fontSize = 20
}
}
}
}
Keys.onReturnPressed: {
if (passphaseInput1.text === passphaseInput2.text) {
root.close()
root.accepted()
}
}
Keys.onEscapePressed: {
root.close()
root.rejected()
}
}
// padding
Rectangle {
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
height: 10
opacity: 0
color: "black"
}
// Ok/Cancel buttons
RowLayout {
id: buttons
spacing: 16
Layout.topMargin: 16
Layout.alignment: Qt.AlignRight
MoneroComponents.StandardButton {
id: cancelButton
text: qsTr("Cancel") + translationManager.emptyString
KeyNavigation.tab: passphaseInput1
onClicked: {
root.close()
root.rejected()
}
}
MoneroComponents.StandardButton {
id: okButton
text: qsTr("Continue") + translationManager.emptyString
KeyNavigation.tab: cancelButton
enabled: passphaseInput1.text === passphaseInput2.text
onClicked: {
root.close()
root.accepted()
}
}
}
}
}
}

View File

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

View File

@@ -17,7 +17,7 @@ if [ ! -d $MONERO_DIR/src ]; then
fi fi
git submodule update --remote git submodule update --remote
git -C $MONERO_DIR fetch git -C $MONERO_DIR fetch
git -C $MONERO_DIR checkout v0.14.1.2 git -C $MONERO_DIR checkout v0.14.1.0
# get monero core tag # get monero core tag
pushd $MONERO_DIR pushd $MONERO_DIR

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

View File

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

View File

@@ -8,7 +8,7 @@ AppName=Monero GUI Wallet
; Thus it's important to keep this stable over releases ; Thus it's important to keep this stable over releases
; With a different "AppName" InnoSetup would treat a mere update as a completely new application and thus mess up ; With a different "AppName" InnoSetup would treat a mere update as a completely new application and thus mess up
AppVersion=0.14.1.2 AppVersion=0.14.1.0
DefaultDirName={pf}\Monero GUI Wallet DefaultDirName={pf}\Monero GUI Wallet
DefaultGroupName=Monero GUI Wallet DefaultGroupName=Monero GUI Wallet
UninstallDisplayIcon={app}\monero-wallet-gui.exe UninstallDisplayIcon={app}\monero-wallet-gui.exe
@@ -21,8 +21,6 @@ DisableWelcomePage=no
LicenseFile=LICENSE LicenseFile=LICENSE
AppPublisher=The Monero Developer Community AppPublisher=The Monero Developer Community
AppPublisherURL=https://getmonero.org AppPublisherURL=https://getmonero.org
TimeStampsInUTC=yes
CompressionThreads=1
UsedUserAreasWarning=no UsedUserAreasWarning=no
; The above directive silences the following compiler warning: ; The above directive silences the following compiler warning:
@@ -70,7 +68,7 @@ Source: "FinishImage.bmp"; Flags: dontcopy
; Monero GUI wallet exe and guide ; Monero GUI wallet exe and guide
Source: "bin\monero-wallet-gui.exe"; DestDir: "{app}"; Flags: ignoreversion Source: "bin\monero-wallet-gui.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "bin\monero-gui-wallet-guide.pdf"; DestDir: "{app}"; Flags: ignoreversion Source: "bin\monero-GUI-guide.pdf"; DestDir: "{app}"; Flags: ignoreversion
; Monero CLI wallet ; Monero CLI wallet
Source: "bin\monero-wallet-cli.exe"; DestDir: "{app}"; Flags: ignoreversion Source: "bin\monero-wallet-cli.exe"; DestDir: "{app}"; Flags: ignoreversion

View File

@@ -34,13 +34,11 @@ You can only build on Windows, and the result is always a
Windows .exe file that can act as a standalone installer for the Windows .exe file that can act as a standalone installer for the
Boron Butterfly GUI wallet. Boron Butterfly GUI wallet.
Note that the installer build process is now reproducible / deterministic. For details check the file [Deterministic.md](Deterministic.md).
The build steps in detail: The build steps in detail:
1. Install *Inno Setup*. You can get it from [here](http://www.jrsoftware.org/isdl.php) 1. Install *Inno Setup*. You can get it from [here](http://www.jrsoftware.org/isdl.php)
2. Get the Inno Setup script plus related files by cloning the whole [monero-gui GitHub repository](https://github.com/monero-project/monero-gui); you will only need the files in the installer directory `installers\windows` however. Depending on development state, additionally you may have to checkout a specific branch, like `release-v0.14`. 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.2`) to this `bin` subdirectory 3. The setup script is written to take the GUI wallet files from a subdirectory named `bin`; so create `installers\windows\bin`, get the zip file of the GUI wallet from [here](https://getmonero.org/downloads/), unpack it somewhere, and copy all the files and subdirectories in the single subdirectory there (currently named `monero-gui-0.14.1.0`) to this `bin` subdirectory
4. Start Inno Setup, load `Monero.iss` and compile it 4. Start Inno Setup, load `Monero.iss` and compile it
5. The result i.e. the finished installer will be the file `mysetup.exe` in the `installers\windows\Output` subdirectory 5. The result i.e. the finished installer will be the file `mysetup.exe` in the `installers\windows\Output` subdirectory

View File

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

View File

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

View File

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

View File

@@ -112,6 +112,25 @@ function roundDownToNearestThousand(_num){
return Math.floor(_num/1000.0)*1000 return Math.floor(_num/1000.0)*1000
} }
function isAlpha(letter){ return letter.match(/^[A-Za-z0-9]+$/) !== null; }
function isLowerCaseChar(letter){ return letter === letter.toLowerCase(); }
function isUpperLock(shift, letter){
if(!isAlpha((letter))) return false;
if(shift) {
if(isLowerCaseChar(letter))
return true;
else
return false;
} else {
if(isLowerCaseChar(letter))
return false;
else
return true;
}
}
function qmlEach(item, properties, ignoredObjectNames, arr){ function qmlEach(item, properties, ignoredObjectNames, arr){
// Traverse QML object tree and return components that match // Traverse QML object tree and return components that match
// via property names. Similar to jQuery("myclass").each(... // via property names. Similar to jQuery("myclass").each(...

View File

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

View File

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

120
main.qml
View File

@@ -31,11 +31,11 @@ import QtQuick.Window 2.0
import QtQuick.Controls 1.1 import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1 import QtQuick.Controls.Styles 1.1
import QtQuick.Dialogs 1.2 import QtQuick.Dialogs 1.2
import Qt.labs.settings 1.0
import moneroComponents.Wallet 1.0 import moneroComponents.Wallet 1.0
import moneroComponents.PendingTransaction 1.0 import moneroComponents.PendingTransaction 1.0
import moneroComponents.NetworkType 1.0 import moneroComponents.NetworkType 1.0
import moneroComponents.Settings 1.0
import "components" import "components"
import "components" as MoneroComponents import "components" as MoneroComponents
@@ -283,7 +283,7 @@ ApplicationWindow {
titleBar.visible = persistentSettings.customDecorations; titleBar.visible = persistentSettings.customDecorations;
} }
function closeWallet(callback) { function closeWallet() {
// Disconnect all listeners // Disconnect all listeners
if (typeof currentWallet !== "undefined" && currentWallet !== null) { if (typeof currentWallet !== "undefined" && currentWallet !== null) {
@@ -306,17 +306,8 @@ ApplicationWindow {
} }
currentWallet = undefined; currentWallet = undefined;
walletManager.closeWallet();
appWindow.showProcessingSplash(qsTr("Closing wallet..."));
if (callback) {
walletManager.closeWalletAsync(function() {
hideProcessingSplash();
callback();
});
} else {
walletManager.closeWallet();
hideProcessingSplash();
}
} }
function connectWallet(wallet) { function connectWallet(wallet) {
@@ -567,21 +558,26 @@ ApplicationWindow {
} }
} }
function onWalletClosed(walletAddress) {
hideProcessingSplash();
console.log(">>> wallet closed: " + walletAddress)
}
function onWalletPassphraseNeeded(){ function onWalletPassphraseNeeded(){
if(rootItem.state !== "normal") return; if(rootItem.state !== "normal") return;
hideProcessingSplash(); hideProcessingSplash();
console.log(">>> wallet passphrase needed: ") console.log(">>> wallet passphrase needed: ")
passwordDialog.onAcceptedPassphraseCallback = function() { passphraseDialog.onAcceptedCallback = function() {
walletManager.onPassphraseEntered(passwordDialog.password); walletManager.onPassphraseEntered(passphraseDialog.passphrase);
this.onWalletOpening(); this.onWalletOpening();
} }
passwordDialog.onRejectedPassphraseCallback = function() { passphraseDialog.onRejectedCallback = function() {
walletManager.onPassphraseEntered("", true); walletManager.onPassphraseEntered("", true);
this.onWalletOpening(); this.onWalletOpening();
} }
passwordDialog.openPassphraseDialog() passphraseDialog.open()
} }
function onWalletUpdate() { function onWalletUpdate() {
@@ -1109,30 +1105,27 @@ ApplicationWindow {
console.log("Hiding processing splash") console.log("Hiding processing splash")
splash.close(); splash.close();
if (!passwordDialog.visible) { leftPanel.enabled = true
leftPanel.enabled = true middlePanel.enabled = true
middlePanel.enabled = true titleBar.enabled = true
titleBar.enabled = true inactiveOverlay.visible = false;
inactiveOverlay.visible = false;
}
} }
// close wallet and show wizard // close wallet and show wizard
function showWizard(){ function showWizard(){
clearMoneroCardLabelText(); clearMoneroCardLabelText();
walletInitialized = false; walletInitialized = false;
closeWallet(function() { closeWallet();
currentWallet = undefined; currentWallet = undefined;
wizard.restart(); wizard.restart();
wizard.wizardState = "wizardHome"; wizard.wizardState = "wizardHome";
rootItem.state = "wizard" rootItem.state = "wizard"
// reset balance // reset balance
leftPanel.balanceText = leftPanel.unlockedBalanceText = walletManager.displayAmount(0); leftPanel.balanceText = leftPanel.unlockedBalanceText = walletManager.displayAmount(0);
fiatApiUpdateBalance(0, 0); fiatApiUpdateBalance(0, 0);
// disable timers // disable timers
userInActivityTimer.running = false; userInActivityTimer.running = false;
simpleModeConnectionTimer.running = false; simpleModeConnectionTimer.running = false;
});
} }
function hideMenu() { function hideMenu() {
@@ -1296,6 +1289,7 @@ ApplicationWindow {
y = (Screen.height - maxWindowHeight) / 2 y = (Screen.height - maxWindowHeight) / 2
// //
walletManager.walletOpened.connect(onWalletOpened); walletManager.walletOpened.connect(onWalletOpened);
walletManager.walletClosed.connect(onWalletClosed);
walletManager.deviceButtonRequest.connect(onDeviceButtonRequest); walletManager.deviceButtonRequest.connect(onDeviceButtonRequest);
walletManager.deviceButtonPressed.connect(onDeviceButtonPressed); walletManager.deviceButtonPressed.connect(onDeviceButtonPressed);
walletManager.checkUpdatesComplete.connect(onWalletCheckUpdatesComplete); walletManager.checkUpdatesComplete.connect(onWalletCheckUpdatesComplete);
@@ -1347,14 +1341,8 @@ ApplicationWindow {
} }
} }
MoneroSettings { Settings {
id: persistentSettings id: persistentSettings
fileName: {
if(isTails && tailsUsePersistence)
return homePath + "/Persistent/Monero/monero-core.conf";
return "";
}
property string language property string language
property string locale property string locale
property string account_name property string account_name
@@ -1506,15 +1494,13 @@ ApplicationWindow {
} }
} }
PasswordDialog { PassphraseDialog {
id: passwordDialog id: passphraseDialog
visible: false visible: false
z: parent.z + 1 z: parent.z + 1
anchors.fill: parent anchors.fill: parent
property var onAcceptedCallback property var onAcceptedCallback
property var onRejectedCallback property var onRejectedCallback
property var onAcceptedPassphraseCallback
property var onRejectedPassphraseCallback
onAccepted: { onAccepted: {
if (onAcceptedCallback) if (onAcceptedCallback)
onAcceptedCallback(); onAcceptedCallback();
@@ -1523,9 +1509,33 @@ ApplicationWindow {
if (onRejectedCallback) if (onRejectedCallback)
onRejectedCallback(); onRejectedCallback();
} }
onAcceptedNewPassword: { }
if (currentWallet.setPassword(passwordDialog.password)) {
appWindow.walletPassword = passwordDialog.password; PasswordDialog {
id: passwordDialog
visible: false
z: parent.z + 1
anchors.fill: parent
property var onAcceptedCallback
property var onRejectedCallback
onAccepted: {
if (onAcceptedCallback)
onAcceptedCallback();
}
onRejected: {
if (onRejectedCallback)
onRejectedCallback();
}
}
NewPasswordDialog {
id: newPasswordDialog
z: parent.z + 1
visible:false
anchors.fill: parent
onAccepted: {
if (currentWallet.setPassword(newPasswordDialog.password)) {
appWindow.walletPassword = newPasswordDialog.password;
informationPopup.title = qsTr("Information") + translationManager.emptyString; informationPopup.title = qsTr("Information") + translationManager.emptyString;
informationPopup.text = qsTr("Password changed successfully") + translationManager.emptyString; informationPopup.text = qsTr("Password changed successfully") + translationManager.emptyString;
informationPopup.icon = StandardIcon.Information; informationPopup.icon = StandardIcon.Information;
@@ -1537,14 +1547,7 @@ ApplicationWindow {
informationPopup.onCloseCallback = null; informationPopup.onCloseCallback = null;
informationPopup.open(); informationPopup.open();
} }
onRejectedNewPassword: {} onRejected: {
onAcceptedPassphrase: {
if (onAcceptedPassphraseCallback)
onAcceptedPassphraseCallback();
}
onRejectedPassphrase: {
if (onRejectedPassphraseCallback)
onRejectedPassphraseCallback();
} }
} }
@@ -2128,8 +2131,8 @@ ApplicationWindow {
console.log("close accepted"); console.log("close accepted");
// Close wallet non async on exit // Close wallet non async on exit
daemonManager.exit(); daemonManager.exit();
walletManager.closeWallet();
closeWallet(Qt.quit); Qt.quit();
} }
function onWalletCheckUpdatesComplete(update) { function onWalletCheckUpdatesComplete(update) {
@@ -2198,7 +2201,6 @@ ApplicationWindow {
function checkInUserActivity() { function checkInUserActivity() {
if(rootItem.state !== "normal") return; if(rootItem.state !== "normal") return;
if(!persistentSettings.lockOnUserInActivity) return; if(!persistentSettings.lockOnUserInActivity) return;
if(passwordDialog.visible) return;
// prompt password after X seconds of inactivity // prompt password after X seconds of inactivity
var epoch = Math.floor((new Date).getTime() / 1000); var epoch = Math.floor((new Date).getTime() / 1000);

View File

@@ -1,6 +1,6 @@
# qml components require at least QT 5.9.0 # qml components require at least QT 5.7.0
lessThan (QT_MAJOR_VERSION, 5) | lessThan (QT_MINOR_VERSION, 9) { lessThan (QT_MAJOR_VERSION, 5) | lessThan (QT_MINOR_VERSION, 7) {
error("Can't build with Qt $${QT_VERSION}. Use at least Qt 5.9.0") error("Can't build with Qt $${QT_VERSION}. Use at least Qt 5.7.0")
} }
TEMPLATE = app TEMPLATE = app
@@ -65,12 +65,10 @@ HEADERS += \
MainApp.h \ MainApp.h \
src/qt/FutureScheduler.h \ src/qt/FutureScheduler.h \
src/qt/ipc.h \ src/qt/ipc.h \
src/qt/mime.h \
src/qt/KeysFiles.h \ src/qt/KeysFiles.h \
src/qt/utils.h \ src/qt/utils.h \
src/qt/prices.h \ src/qt/prices.h
src/qt/macoshelper.h \
src/qt/MoneroSettings.h \
src/qt/TailsOS.h
SOURCES += main.cpp \ SOURCES += main.cpp \
filter.cpp \ filter.cpp \
@@ -101,11 +99,10 @@ SOURCES += main.cpp \
MainApp.cpp \ MainApp.cpp \
src/qt/FutureScheduler.cpp \ src/qt/FutureScheduler.cpp \
src/qt/ipc.cpp \ src/qt/ipc.cpp \
src/qt/mime.cpp \
src/qt/KeysFiles.cpp \ src/qt/KeysFiles.cpp \
src/qt/utils.cpp \ src/qt/utils.cpp \
src/qt/prices.cpp \ src/qt/prices.cpp
src/qt/MoneroSettings.cpp \
src/qt/TailsOS.cpp
CONFIG(DISABLE_PASS_STRENGTH_METER) { CONFIG(DISABLE_PASS_STRENGTH_METER) {
HEADERS -= src/zxcvbn-c/zxcvbn.h HEADERS -= src/zxcvbn-c/zxcvbn.h
@@ -337,8 +334,7 @@ linux {
-llmdb \ -llmdb \
-lsodium \ -lsodium \
-lhidapi-libusb \ -lhidapi-libusb \
-lcrypto $$TREZOR_LINKER \ -lcrypto $$TREZOR_LINKER
-lX11
if(!android) { if(!android) {
LIBS+= \ LIBS+= \
@@ -363,8 +359,6 @@ macx {
# message("using static libraries") # message("using static libraries")
# LIBS+= -Wl,-Bstatic # LIBS+= -Wl,-Bstatic
# } # }
QT += macextras
OBJECTIVE_SOURCES += src/qt/macoshelper.mm
LIBS+= \ LIBS+= \
-L/usr/local/lib \ -L/usr/local/lib \
-L/usr/local/opt/openssl/lib \ -L/usr/local/opt/openssl/lib \
@@ -378,7 +372,6 @@ macx {
-lboost_chrono \ -lboost_chrono \
-lboost_program_options \ -lboost_program_options \
-framework CoreFoundation \ -framework CoreFoundation \
-framework AppKit \
-lhidapi \ -lhidapi \
-lssl \ -lssl \
-lsodium \ -lsodium \

View File

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

View File

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

View File

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

View File

@@ -145,7 +145,7 @@ Rectangle {
ListView { ListView {
id: addressBookListView id: addressBookListView
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true anchors.fill: parent
clip: true clip: true
boundsBehavior: ListView.StopAtBounds boundsBehavior: ListView.StopAtBounds
interactive: false interactive: false

View File

@@ -49,9 +49,9 @@ Rectangle {
property var model property var model
property int sideMargin: 50 property int sideMargin: 50
property var initialized: false property var initialized: false
property int txMax: Math.max(5, ((appWindow.height - 250) / 60)) property int txMax: 5
property int txOffset: 0 property int txOffset: 0
property int txPage: (txOffset / txMax) + 1 property int txPage: (txOffset / 5) + 1
property int txCount: 0 property int txCount: 0
property var sortSearchString: null property var sortSearchString: null
property bool sortDirection: true // true = desc, false = asc property bool sortDirection: true // true = desc, false = asc
@@ -67,8 +67,6 @@ Rectangle {
color: "transparent" color: "transparent"
onTxMaxChanged: root.updateDisplay(root.txOffset, root.txMax);
ColumnLayout { ColumnLayout {
id: pageRoot id: pageRoot
anchors.topMargin: 40 anchors.topMargin: 40
@@ -251,6 +249,7 @@ Rectangle {
font.pixelSize: 15 font.pixelSize: 15
text: qsTr("Blockheight") + translationManager.emptyString text: qsTr("Blockheight") + translationManager.emptyString
color: root.sortBy === "blockheight" ? MoneroComponents.Style.defaultFontColor : MoneroComponents.Style.dimmedFontColor color: root.sortBy === "blockheight" ? MoneroComponents.Style.defaultFontColor : MoneroComponents.Style.dimmedFontColor
anchors.verticalCenter: parent.verticalCenter
themeTransition: false themeTransition: false
} }
@@ -311,6 +310,7 @@ Rectangle {
text: qsTr("Date") + translationManager.emptyString text: qsTr("Date") + translationManager.emptyString
color: root.sortBy === "timestamp" ? MoneroComponents.Style.defaultFontColor : MoneroComponents.Style.dimmedFontColor color: root.sortBy === "timestamp" ? MoneroComponents.Style.defaultFontColor : MoneroComponents.Style.dimmedFontColor
themeTransition: false themeTransition: false
anchors.verticalCenter: parent.verticalCenter
} }
MoneroEffects.ImageMask { MoneroEffects.ImageMask {
@@ -370,6 +370,7 @@ Rectangle {
text: qsTr("Amount") + translationManager.emptyString text: qsTr("Amount") + translationManager.emptyString
color: root.sortBy === "amount" ? MoneroComponents.Style.defaultFontColor : MoneroComponents.Style.dimmedFontColor color: root.sortBy === "amount" ? MoneroComponents.Style.defaultFontColor : MoneroComponents.Style.dimmedFontColor
themeTransition: false themeTransition: false
anchors.verticalCenter: parent.verticalCenter
} }
MoneroEffects.ImageMask { MoneroEffects.ImageMask {
@@ -1342,14 +1343,13 @@ Rectangle {
root.updateDisplay(root.txOffset, root.txMax); root.updateDisplay(root.txOffset, root.txMax);
} }
function reset(keepDate) { function reset() {
root.txOffset = 0; root.txOffset = 0;
root.txMax = 5;
if (typeof root.model !== 'undefined' && root.model != null) { if (typeof root.model !== 'undefined' && root.model != null) {
if (!keepDate) { root.model.dateFromFilter = "2014-04-18" // genesis block
root.model.dateFromFilter = "2014-04-18" // genesis block root.model.dateToFilter = "9999-09-09" // fix before september 9999
root.model.dateToFilter = "9999-09-09" // fix before september 9999
}
// negative values disable filters here; // negative values disable filters here;
root.model.amountFromFilter = -1; root.model.amountFromFilter = -1;
root.model.amountToFilter = -1; root.model.amountToFilter = -1;
@@ -1387,8 +1387,6 @@ Rectangle {
txs.push(item); txs.push(item);
} else if(item.blockheight.toString().startsWith(root.sortSearchString)) { } else if(item.blockheight.toString().startsWith(root.sortSearchString)) {
txs.push(item); txs.push(item);
} else if(item.tx_note.toLowerCase().indexOf(root.sortSearchString.toLowerCase()) !== -1) {
txs.push(item);
} else if (item.hash.startsWith(root.sortSearchString)){ } else if (item.hash.startsWith(root.sortSearchString)){
txs.push(item); txs.push(item);
} }
@@ -1706,6 +1704,6 @@ Rectangle {
function onPageClosed(){ function onPageClosed(){
root.initialized = false; root.initialized = false;
root.reset(true); root.reset();
} }
} }

View File

@@ -116,11 +116,11 @@ Rectangle {
MoneroComponents.LineEdit { MoneroComponents.LineEdit {
Layout.fillWidth: true Layout.fillWidth: true
id: walletCreationHeight
readOnly: true readOnly: true
copyButton: true copyButton: true
labelText: qsTr("Block #") + translationManager.emptyString labelText: qsTr("Block #") + translationManager.emptyString
fontSize: 16 fontSize: 16
text: currentWallet.walletCreationHeight
} }
} }
@@ -261,7 +261,6 @@ Rectangle {
function onPageCompleted() { function onPageCompleted() {
console.log("keys page loaded"); console.log("keys page loaded");
walletCreationHeight.text = currentWallet.walletCreationHeight
secretViewKey.text = currentWallet.secretViewKey secretViewKey.text = currentWallet.secretViewKey
publicViewKey.text = currentWallet.publicViewKey publicViewKey.text = currentWallet.publicViewKey
secretSpendKey.text = (!currentWallet.viewOnly) ? currentWallet.secretSpendKey : "" secretSpendKey.text = (!currentWallet.viewOnly) ? currentWallet.secretSpendKey : ""

View File

@@ -101,7 +101,7 @@ Rectangle {
ListView { ListView {
id: subaddressListView id: subaddressListView
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true anchors.fill: parent
clip: true clip: true
boundsBehavior: ListView.StopAtBounds boundsBehavior: ListView.StopAtBounds
interactive: false interactive: false
@@ -256,7 +256,6 @@ Rectangle {
inputDialog.onAcceptedCallback = function() { inputDialog.onAcceptedCallback = function() {
appWindow.currentWallet.subaddress.addRow(appWindow.currentWallet.currentSubaddressAccount, inputDialog.inputText) appWindow.currentWallet.subaddress.addRow(appWindow.currentWallet.currentSubaddressAccount, inputDialog.inputText)
current_subaddress_table_index = appWindow.currentWallet.numSubaddresses(appWindow.currentWallet.currentSubaddressAccount) - 1 current_subaddress_table_index = appWindow.currentWallet.numSubaddresses(appWindow.currentWallet.currentSubaddressAccount) - 1
subaddressListView.currentIndex = current_subaddress_table_index
} }
inputDialog.onRejectedCallback = null; inputDialog.onRejectedCallback = null;
inputDialog.open() inputDialog.open()

View File

@@ -93,8 +93,9 @@ Item {
anchors.right: parent.right anchors.right: parent.right
Item { Item {
Layout.preferredHeight: 220 height: 220
Layout.fillWidth: true anchors.left: parent.left
anchors.right: parent.right
Rectangle { Rectangle {
id: tracker id: tracker
@@ -257,7 +258,8 @@ Item {
Item { Item {
Layout.preferredHeight: 40 Layout.preferredHeight: 40
Layout.fillWidth: true anchors.left: parent.left
anchors.right: parent.right
Item { Item {
width: (parent.width - qrImg.width) - (50) width: (parent.width - qrImg.width) - (50)
@@ -522,7 +524,8 @@ Item {
Item { Item {
Layout.topMargin: 32 Layout.topMargin: 32
Layout.preferredHeight: 40 Layout.preferredHeight: 40
Layout.fillWidth: true anchors.left: parent.left
anchors.right: parent.right
ColumnLayout { ColumnLayout {
spacing: 16 spacing: 16
@@ -627,7 +630,7 @@ Item {
in_txpool = true; in_txpool = true;
} else { } else {
if (blockchainHeight == null) if (blockchainHeight == null)
blockchainHeight = walletManager.blockchainHeight() blockchainHeight = appWindow.currentWallet.blockChainHeight()
confirmations = blockchainHeight - blockHeight - 1 confirmations = blockchainHeight - blockHeight - 1
displayAmount = model.data(idx, TransactionHistoryModel.TransactionDisplayAmountRole); displayAmount = model.data(idx, TransactionHistoryModel.TransactionDisplayAmountRole);
} }

View File

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

View File

@@ -339,7 +339,7 @@ Rectangle {
onClicked: { onClicked: {
passwordDialog.onAcceptedCallback = function() { passwordDialog.onAcceptedCallback = function() {
if(appWindow.walletPassword === passwordDialog.password){ if(appWindow.walletPassword === passwordDialog.password){
passwordDialog.openNewPasswordDialog() newPasswordDialog.open()
} else { } else {
informationPopup.title = qsTr("Error") + translationManager.emptyString; informationPopup.title = qsTr("Error") + translationManager.emptyString;
informationPopup.text = qsTr("Wrong password") + translationManager.emptyString; informationPopup.text = qsTr("Wrong password") + translationManager.emptyString;

View File

@@ -96,7 +96,9 @@
<file>pages/SharedRingDB.qml</file> <file>pages/SharedRingDB.qml</file>
<file>components/effects/ImageMask.qml</file> <file>components/effects/ImageMask.qml</file>
<file>components/IconButton.qml</file> <file>components/IconButton.qml</file>
<file>components/PassphraseDialog.qml</file>
<file>components/PasswordDialog.qml</file> <file>components/PasswordDialog.qml</file>
<file>components/NewPasswordDialog.qml</file>
<file>components/InputDialog.qml</file> <file>components/InputDialog.qml</file>
<file>components/ProcessingSplash.qml</file> <file>components/ProcessingSplash.qml</file>
<file>components/ProgressBar.qml</file> <file>components/ProgressBar.qml</file>
@@ -251,6 +253,5 @@
<file>images/copy.svg</file> <file>images/copy.svg</file>
<file>images/edit.svg</file> <file>images/edit.svg</file>
<file>images/arrow-right-in-circle-outline-medium-white.svg</file> <file>images/arrow-right-in-circle-outline-medium-white.svg</file>
<file>images/tails-grey.png</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@@ -524,8 +524,7 @@ bool Wallet::submitTxFile(const QString &fileName) const
void Wallet::commitTransactionAsync(PendingTransaction *t) void Wallet::commitTransactionAsync(PendingTransaction *t)
{ {
m_scheduler.run([this, t] { m_scheduler.run([this, t] {
auto txIdList = t->txid(); // retrieve before commit emit transactionCommitted(t->commit(), t, t->txid());
emit transactionCommitted(t->commit(), t, txIdList);
}); });
} }

View File

@@ -351,7 +351,7 @@ signals:
void walletCreationHeightChanged(); void walletCreationHeightChanged();
void deviceButtonRequest(quint64 buttonCode); void deviceButtonRequest(quint64 buttonCode);
void deviceButtonPressed(); void deviceButtonPressed();
void transactionCommitted(bool status, PendingTransaction *t, const QStringList& txid); void transactionCommitted(bool status, PendingTransaction *t, QStringList txid);
void heightRefreshed(quint64 walletHeight, quint64 daemonHeight, quint64 targetHeight) const; void heightRefreshed(quint64 walletHeight, quint64 daemonHeight, quint64 targetHeight) const;
// emitted when transaction is created async // emitted when transaction is created async

View File

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

View File

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

View File

@@ -1,208 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
****************************************************************************/
// Copyright (c) 2014-2019, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <QtCore>
#include <QMetaObject>
#include <QSettings>
#include <QPointer>
#include <QJSValue>
#include <QHash>
#include <QMetaProperty>
#include "src/qt/MoneroSettings.h"
/*!
\qmlmodule moneroSettings 1.0
\title Monero Settings QML Component
\ingroup qmlmodules
\brief Provides persistent platform-independent application settings.
This component was introduced in order to have control over where the
configuration file is written. This is needed for Tails OS and
portable installations.
For more information, see: https://doc.qt.io/qt-5/qml-qt-labs-settings-settings.html and
https://github.com/qt/qtdeclarative/blob/v5.12.0/src/imports/settings/qqmlsettings.cpp
To use this module, import the module with the following line:
\code
import moneroComponents.Settings 1.0
\endcode
Usage:
\code
MoneroSettings { id: persistentSettings, property bool foo: true }
\endcode
@TODO: Remove this QML component after migrating to Qt >= 5.12.0, as
`Qt.labs.settings` provides the fileName via a Q_PROPERTY
*/
void MoneroSettings::load()
{
const QMetaObject *mo = this->metaObject();
const int offset = mo->propertyOffset();
const int count = mo->propertyCount();
for (int i = offset; i < count; ++i) {
QMetaProperty property = mo->property(i);
const QVariant previousValue = readProperty(property);
const QVariant currentValue = this->m_settings->value(property.name(), previousValue);
if (!currentValue.isNull() && (!previousValue.isValid()
|| (currentValue.canConvert(previousValue.type()) && previousValue != currentValue))) {
property.write(this, currentValue);
#ifdef QT_DEBUG
qDebug() << "QQmlSettings: load" << property.name() << "setting:" << currentValue << "default:" << previousValue;
#endif
}
// ensure that a non-existent setting gets written
// even if the property wouldn't change later
if (!this->m_settings->contains(property.name()))
this->_q_propertyChanged();
// setup change notifications on first load
if (!this->m_initialized && property.hasNotifySignal()) {
static const int propertyChangedIndex = mo->indexOfSlot("_q_propertyChanged()");
int signalIndex = property.notifySignalIndex();
QMetaObject::connect(this, signalIndex, this, propertyChangedIndex);
}
}
}
void MoneroSettings::_q_propertyChanged()
{
// Called on QML property change
const QMetaObject *mo = this->metaObject();
const int offset = mo->propertyOffset();
const int count = mo->propertyCount();
for (int i = offset; i < count; ++i) {
const QMetaProperty &property = mo->property(i);
const QVariant value = readProperty(property);
this->m_changedProperties.insert(property.name(), value);
#ifdef QT_DEBUG
//qDebug() << "QQmlSettings: cache" << property.name() << ":" << value;
#endif
}
if (this->m_timerId != 0)
this->killTimer(this->m_timerId);
this->m_timerId = this->startTimer(settingsWriteDelay);
}
QVariant MoneroSettings::readProperty(const QMetaProperty &property) const
{
QVariant var = property.read(this);
if (var.userType() == qMetaTypeId<QJSValue>())
var = var.value<QJSValue>().toVariant();
return var;
}
void MoneroSettings::init()
{
if (!this->m_initialized) {
this->m_settings = this->m_fileName.isEmpty() ? new QSettings() : new QSettings(this->m_fileName, QSettings::IniFormat);
#ifdef QT_DEBUG
qDebug() << "QQmlSettings: stored at" << this->m_settings->fileName();
#endif
this->load();
this->m_initialized = true;
}
}
void MoneroSettings::reset()
{
if (this->m_initialized && this->m_settings && !this->m_changedProperties.isEmpty())
this->store();
if (this->m_settings)
delete this->m_settings;
}
void MoneroSettings::store()
{
QHash<const char *, QVariant>::const_iterator it = this->m_changedProperties.constBegin();
while (it != this->m_changedProperties.constEnd()) {
this->m_settings->setValue(it.key(), it.value());
#ifdef QT_DEBUG
//qDebug() << "QQmlSettings: store" << it.key() << ":" << it.value();
#endif
++it;
}
this->m_changedProperties.clear();
}
void MoneroSettings::setFileName(const QString &fileName)
{
if (fileName != this->m_fileName) {
this->reset();
this->m_fileName = fileName;
if (this->m_initialized)
this->load();
}
}
QString MoneroSettings::fileName() const
{
return this->m_fileName;
}
void MoneroSettings::timerEvent(QTimerEvent *event)
{
if (event->timerId() == this->m_timerId) {
killTimer(this->m_timerId);
this->m_timerId = 0;
this->store();
}
QObject::timerEvent(event);
}
void MoneroSettings::componentComplete()
{
this->init();
}
void MoneroSettings::classBegin()
{
}
MoneroSettings::MoneroSettings(QObject *parent) :
QObject(parent)
{
}

View File

@@ -1,81 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
****************************************************************************/
// Copyright (c) 2014-2019, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef MONEROSETTINGS_H
#define MONEROSETTINGS_H
#include <QtQml/qqmlparserstatus.h>
#include <QGuiApplication>
#include <QClipboard>
#include <QObject>
#include <QDebug>
#include <qsettings.h>
static const int settingsWriteDelay = 500; // ms
class MoneroSettings : public QObject, public QQmlParserStatus
{
Q_OBJECT
Q_INTERFACES(QQmlParserStatus)
Q_PROPERTY(QString fileName READ fileName WRITE setFileName FINAL)
public:
explicit MoneroSettings(QObject *parent = nullptr);
QString fileName() const;
void setFileName(const QString &fileName);
public slots:
void _q_propertyChanged();
protected:
void timerEvent(QTimerEvent *event) override;
void classBegin() override;
void componentComplete() override;
private:
QVariant readProperty(const QMetaProperty &property) const;
void init();
void reset();
void load();
void store();
QHash<const char *, QVariant> m_changedProperties;
QSettings *m_settings = NULL;
QString m_fileName = QString("");
bool m_initialized = false;
int m_timerId = 0;
};
#endif // MONEROSETTINGS_H

View File

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

View File

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

View File

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

View File

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

View File

@@ -26,15 +26,11 @@
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef MACOSHELPER_H #ifndef MIME_H
#define MACOSHELPER_H #define MIME_H
class MacOSHelper #include <QApplication>
{
MacOSHelper() {}
public: void registerXdgMime(QApplication &app);
static bool isCapsLock();
};
#endif //MACOSHELPER_H #endif // MIME_H

View File

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

View File

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

View File

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

View File

@@ -83,7 +83,7 @@ ColumnLayout {
WizardHeader{ WizardHeader{
title: qsTr("Give your wallet a password") + translationManager.emptyString title: qsTr("Give your wallet a password") + translationManager.emptyString
subtitle: qsTr("This password cannot be recovered. If you forget it then the wallet will have to be restored from your %1.").arg(!wizardController.walletOptionsIsRecoveringFromDevice ? qsTr("25 word mnemonic seed") : qsTr("hardware wallet"))+ translationManager.emptyString subtitle: qsTr("This password cannot be recovered. If you forget it then the wallet will have to be restored from its 25 word mnemonic seed.") + translationManager.emptyString
} }
MoneroComponents.WarningBox { MoneroComponents.WarningBox {
@@ -97,12 +97,23 @@ ColumnLayout {
TextInput { TextInput {
id: progressText id: progressText
Layout.topMargin: 6 anchors.top: parent.top
Layout.bottomMargin: 6 anchors.topMargin: 6
font.family: MoneroComponents.Style.fontMedium.name font.family: MoneroComponents.Style.fontMedium.name
font.pixelSize: 14 font.pixelSize: 14
font.bold: false font.bold: false
color: MoneroComponents.Style.defaultFontColor color: MoneroComponents.Style.defaultFontColor
text: root.passwordStrengthText + '-'
height: 18
passwordCharacter: "*"
}
TextInput {
id: progressTextValue
font.family: MoneroComponents.Style.fontMedium.name
font.pixelSize: 13
font.bold: true
color: MoneroComponents.Style.defaultFontColor
height: 18 height: 18
passwordCharacter: "*" passwordCharacter: "*"
} }

View File

@@ -273,13 +273,12 @@ Rectangle {
clip: true clip: true
ScrollBar.vertical: ScrollBar { ScrollBar.vertical: ScrollBar {
parent: wizardController parent: wizardFlickable.parent
anchors.left: parent.right anchors.left: parent.right
anchors.leftMargin: -14 // 10 margin + 4 scrollbar width anchors.leftMargin: 3
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: persistentSettings.customDecorations ? 60 : 10 anchors.topMargin: 4
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.bottomMargin: persistentSettings.customDecorations ? 15 : 10
} }
onFlickingChanged: { onFlickingChanged: {
@@ -499,15 +498,15 @@ Rectangle {
splash.close() splash.close()
console.log(">>> wallet passphrase needed: "); console.log(">>> wallet passphrase needed: ");
passwordDialog.onAcceptedPassphraseCallback = function() { passphraseDialog.onAcceptedCallback = function() {
walletManager.onPassphraseEntered(passwordDialog.password); walletManager.onPassphraseEntered(passphraseDialog.passphrase);
creatingWalletDeviceSplash(); creatingWalletDeviceSplash();
} }
passwordDialog.onRejectedPassphraseCallback = function() { passphraseDialog.onRejectedCallback = function() {
walletManager.onPassphraseEntered("", true); walletManager.onPassphraseEntered("", true);
creatingWalletDeviceSplash(); creatingWalletDeviceSplash();
} }
passwordDialog.openPassphraseDialog() passphraseDialog.open()
} }
function onDeviceButtonRequest(code){ function onDeviceButtonRequest(code){

View File

@@ -151,7 +151,7 @@ Rectangle {
labelFontSize: 14 labelFontSize: 14
copyButton: false copyButton: false
readOnly: true readOnly: true
text: Utils.roundDownToNearestThousand(wizardController.m_wallet ? wizardController.m_wallet.walletCreationHeight : 0) text: Utils.roundDownToNearestThousand(wizardController.m_wallet.walletCreationHeight)
} }
MoneroComponents.WarningBox { MoneroComponents.WarningBox {

View File

@@ -69,7 +69,7 @@ ColumnLayout {
TextArea { TextArea {
Layout.fillWidth: true Layout.fillWidth: true
Layout.alignment: Qt.AlignCenter anchors.horizontalCenter: parent.horizontalCenter
visible: parent.subtitle !== "" visible: parent.subtitle !== ""
color: MoneroComponents.Style.dimmedFontColor color: MoneroComponents.Style.dimmedFontColor

View File

@@ -60,7 +60,7 @@ Rectangle {
id: textWelcome id: textWelcome
opacity: 0 opacity: 0
Layout.preferredWidth: parent.width / 1.3 Layout.preferredWidth: parent.width / 1.3
Layout.alignment: Qt.AlignCenter anchors.horizontalCenter: parent.horizontalCenter
color: MoneroComponents.Style.defaultFontColor color: MoneroComponents.Style.defaultFontColor
text: "Welcome - Wilkommen - Bonvenon - Bienvenido - Bienvenue - Välkommen - Selamat datang - Benvenuto - 歡迎 - Welkom - Bem Vindo - добро пожаловать" text: "Welcome - Wilkommen - Bonvenon - Bienvenido - Bienvenue - Välkommen - Selamat datang - Benvenuto - 歡迎 - Welkom - Bem Vindo - добро пожаловать"
@@ -97,7 +97,7 @@ Rectangle {
} }
Layout.preferredWidth: size Layout.preferredWidth: size
Layout.preferredHeight: size Layout.preferredHeight: size
Layout.alignment: Qt.AlignCenter anchors.horizontalCenter: parent.horizontalCenter
mipmap: true mipmap: true
property bool animSlow: false property bool animSlow: false
@@ -149,7 +149,7 @@ Rectangle {
id: buttonsGrid id: buttonsGrid
opacity: 0 opacity: 0
columns: isMobile ? 1 : 2 columns: isMobile ? 1 : 2
Layout.alignment: Qt.AlignCenter anchors.horizontalCenter: parent.horizontalCenter
Layout.topMargin: 20 Layout.topMargin: 20
Layout.fillWidth: true Layout.fillWidth: true
columnSpacing: 20 columnSpacing: 20
@@ -190,7 +190,7 @@ Rectangle {
MoneroComponents.TextPlain { MoneroComponents.TextPlain {
id: versionText id: versionText
opacity: 0 opacity: 0
Layout.alignment: Qt.AlignCenter anchors.horizontalCenter: parent.horizontalCenter
font.bold: true font.bold: true
font.pixelSize: 12 font.pixelSize: 12
font.family: MoneroComponents.Style.fontRegular.name font.family: MoneroComponents.Style.fontRegular.name

View File

@@ -57,6 +57,12 @@ ColumnLayout {
value: wizardController.language_language value: wizardController.language_language
} }
WizardSummaryItem {
Layout.fillWidth: true
header: qsTr("Wallet name") + translationManager.emptyString
value: walletOptionsName
}
WizardSummaryItem { WizardSummaryItem {
Layout.fillWidth: true Layout.fillWidth: true
header: qsTr("Restore height") + translationManager.emptyString header: qsTr("Restore height") + translationManager.emptyString